4
头图

Hello, brave friends, hello everyone, I am your little five, the king of the mouth, I am in good health, and my brain is not sick.

I have a wealth of hair loss skills, which can make you a veteran celebrity.

It is my main theme that I will write it when I look at it, and it is my characteristic to pick my feet. There is a trace of strength in the humble. The stupid blessing of a fool is the greatest comfort to me.

Welcome to fifth of algorithm Series sail articles - sorting algorithm.

Preface

This series of articles is based on the two books "Algorithm Graphics" and "Learning JavaScript Algorithms" as the core, and the rest of the materials are supplemented by the author's humble opinion. Strive to use simple and interesting language to lead everyone to the wonder of the algorithm world. Here The series of articles are from shallow to deep, one by one, and then we use the sorting algorithm to open the first chapter of this great route.

This article explains the following five common sorts, which are three simple sorts: "bubble sort", "selective sort", "insertion sort" and two complex sorts: "quick sort", "merge sort".

Each sorting is basic idea, process diagram, algorithm analysis, time and space complexity, and code implementation.

<Supplementary Notes> recommends to first understand the execution order of the program stack, you can read "Algorithm Diagram-3.3 Stack" , which will make learning fast sorting and merging twice the result with half the effort; this chapter is mainly used to understand the execution order of recursion, I think , If quick sorting and merging are difficult to understand, the bottom line is that recursion is not well understood; this chapter can lay the cornerstone for the following algorithm learning; [The above does not affect the reading of this article, everyone varies from person to person, please choose by

Bubble Sort

👺 Basic idea: <Adjacent elements pairwise contrast to find the maximum >

👺 Process diagram:

👺 Algorithm analysis:

  1. Outer loop: length - 1 times
  2. Inner loop: length-1-The number of elements has been determined (equivalent to the index of the outer loop) times
  3. Compare the size of adjacent elements, if arr[j] > arr[j + 1] , then interchange elements

👺 Complexity:

According to the above analysis, the outer loop is $n-1$ times, and the inner loop is $(n-1)/2$ times, so the total number of executions is $(n-1)^2 / 2$

tips: time complexity and space complexity do not care about low-order variables, coefficients and constants

Time complexity: The highest item above is $n^2$, so the time complexity is $O(n^2)$

space complexity: only temp variables require memory space, so the space complexity is O(1)$

👺 Code implementation:

const bubbleSort = (arr: number[]) => {
  for (let i = 0; i < arr.length - 1; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        let temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
  return arr;
}

Select sort

👺 Basic idea: < select the smallest value >

👺 Process diagram:

👺 Algorithm analysis:

  1. Outer loop: length - 1 times
  2. Inner loop: loop from i + 1 , loop length - (i + 1) times
  3. Record the outer loop index as minIndex , in the inner loop, if a smaller value is found, update minIndex
  4. Swap the positions of arr[index] and arr[minIndex]

👺 Complexity:

According to the above analysis, the outer loop is $n-1$ times, and the inner loop is $(n-1)/2$ times, so the total number of executions is $(n-1)^2 / 2$

Time complexity: $O(n^2)$

space complexity: temp and minIndex variables need memory space, because they do not care about the coefficients, so it is $O(1)$

👺 Code implementation:

const selectSort = (arr: number[]) => {
  let minIndex: number;

  for (let i = 0; i < arr.length; i++) {
    minIndex = i;

    for (let j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[minIndex]) minIndex = j;
    }
    
    let temp = arr[minIndex];
    arr[minIndex] = arr[i];
    arr[i] = temp;
  }

  return arr;
}

Insertion sort

👺 Basic idea: <From left to right confirm the position of the element item >

👺 Process diagram:

👺 Algorithm analysis:

  1. Outer loop: start loop from 1, loop times length - 1
  2. Inner loop: j = i , compare with the previous item one by one, exchange positions if it is smaller than the previous item, until it is inserted in the correct position

👺 Complexity:

According to the above analysis, the outer loop is $n-1$ times, and the inner loop is $n/2$ times, so the total number of executions is $n * (n-1) / 2$

time complexity: $O(n^2)$

space complexity: only temp variables need memory space, so it is $O(1)$

👺 Code implementation:

const insertSort = (arr: number[]) => {
  for (let i = 1; i < arr.length; i++) {
    for (let j = i; j > 0; j--) {
      if (arr[j - 1] > arr[j]) {
        let temp = arr[j - 1];
        arr[j - 1] = arr[j];
        arr[j] = temp;
      }
    }
  }
  return arr;
}

Quick sort

👺 Basic idea: < and merge > (we select the middle item of the array as the reference value)

👺 Process diagram:

👺 Algorithm analysis:

  1. The idea of quick sorting is based on a value, the ones smaller than the benchmark value are pushed into the left array, and those larger than the benchmark value are pushed into the right array; the recursive call until the array is empty; the left and right arrays are spliced with the reference value, and all are spliced After forming the required array;
  2. By splice and Math.floor(arr.length / 2) acquires middle value;
  3. Understand the calling sequence of the program stack, you can understand the quick sort well;

👺 Complexity:

The complexity of the recursive process divided by the reference value is $logn$; for loop is $n$

time complexity: $O(nlogn)$

space complexity: space complexity is the number of recursive layers -> $O(logn)$

👺 Code implementation:

const quickSort = (arr: number[]): number[] => {
  if (!arr.length) return [];

  let leftArr: number[] = [];
  let rightArr: number[] = [];
  let middle = arr.splice(Math.floor(arr.length / 2), 1)[0];
  
  arr.forEach(item => {
    item < middle ? leftArr.push(item) : rightArr.push(item);
  })

  return quickSort(leftArr).concat(middle, quickSort(rightArr));
}

Merge sort

👺 Basic idea: < merge the ordered array into a larger ordered array >

👺 Process diagram:

👺 Algorithm analysis:

  1. Merge sort uses the idea of divide and conquer, that is, the original problem is decomposed into sub-problems, and the sub-problems are merged after solving the sub-problems; therefore, the large array is decomposed into small arrays until there is only one element in the array, at which time the array is all ordered , The ordered arrays are merged and sorted to form a new ordered array, and the sorting is completed after all merges;
  2. Get the index of the intermediate item through Math.floor(arr.length / 2) slice the array into two through the index and 060ff61a9110b2;
  3. When merging, compare the first item of the left and right arrays, push the smaller value into the new array, and update the left and right arrays shift
  4. Understand the calling order of the program stack, you can understand the merge sort well;

👺 Complexity:

[Minutes] Dichotomous operation -> complexity is $logn$; [combined] while loop -> complexity is $n$;

Time complexity: $O(nlogn)$

space complexity: space complexity is the number of recursive layers and the space occupied by temporary arrays -> $logn+n$, so the space complexity is $O(n)$

👺 Code implementation:

const mergeSort = (arr: number[]): number[] => { // 拆分
  if (arr.length <= 1) return arr;

  let middle = Math.floor(arr.length / 2);
  let leftArr = arr.slice(0, middle);
  let rightArr = arr.slice(middle);

  return merge(mergeSort(leftArr), mergeSort(rightArr));
}

const merge = (leftArr: number[], rightArr: number[]) => { // 合并
  let result: number[] = [];

  while (leftArr.length || rightArr.length) {
    if (leftArr.length && rightArr.length) {
      leftArr[0] < rightArr[0]
        ? result.push(leftArr.shift() as number)
        : result.push(rightArr.shift() as number);
    } else {
      if (leftArr.length) result.push(leftArr.shift() as number);
      if (rightArr.length) result.push(rightArr.shift() as number);
    }
  }

  return result;
}


黄刀小五
305 声望22 粉丝

前端开发攻城狮, 擅长搬砖, 精通ctrl + c & ctrl + v, 日常bug缔造者.