“This is the first day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021”

preface

The front-end algorithm series is a record of my algorithm learning, which mainly analyzes the learning algorithm knowledge from common algorithms, data structure, algorithm thinking and common skills. It realizes deliberate practice through LeetCode platform, and practices Feynman learning method through digging gold and the output of STATION B. I will update the quality content and synchronously update it to Nuggets, B station and Github in the future, so as to record the complete process of learning algorithm. Welcome to communicate, like and collect more, let us make progress together, daydayUp 👊

Directory address: directory section

Code address: Github

Bilibili – 100 days algorithm series

I. Classification of algorithms

  • Comparison class: through the comparison of elements to achieve, time complexity can not break O(nlogn)
  • Non-comparison classes: There is no need to compare the size of elements

Second, algorithm complexity

Related knowledge supplement

  • Time complexity: A functional relationship between the time it takes to execute code and the amount of data
  • Spatial complexity: The functional relationship between the amount of space required to execute code and the amount of data
  • Stability: Whether two equal data are sorted in the same order

Three, ten sorting algorithm details

Online sorting algorithm demonstration

Introduction: the implementation of the code may be slightly different, but the main idea remains the same, in order to make the code more concise out of part of the functional code

Bubble Sort

describe

Compare the two elements in turn, moving the smaller value to the front, while the larger element bubbles to the end

The illustration

code

function bubbleSort(nums) {
    let len = nums.length
    for(let i=len; i>0; i--) {
        for(let j=0; j<i-1; j++) {
            if (nums[j] > nums[j+1]) temp(nums, j, j + 1)}}}// Switch the position of the data deconstruction version
function temp(nums, i, j) {
    [nums[i], nums[j]] = [nums[j], nums[i]]
}
Copy the code

3.1 Quick Sort (Quick Sort)

describe

Pick a pivot, place greater than or equal to the pivot to the right, and less than the pivot to the left, and recurse

The illustration

code

// This function bases on the first element of the array
function quickSort(nums) {
    if (nums.length < 2) return nums
    let left = [], right = []
    while(nums.length > 1) {
        let num = nums.pop()
        if (num >= nums[0]) {
            right.push(num)
        } else {
            left.push(num)
        }
    }
    return [...quickSort(left), nums[0], ...quickSort(right)]
}
Copy the code

3.2 Selection Sort

describe

Pick the smallest element in the array at a time

The illustration

code

function selectionSort(nums) {
    let i = 0, 
        len = nums.length
    while(i < len) {
        let min = getMinIdx(nums, i)
        temp(nums, i, min)
        i++
    }
    return nums
}

// Get the smallest array
function getMinIdx(nums, i) {
    let min = 0
    for(let j=i; j < nums.length; j++) {
        if (nums[j] < nums[min]) min = j
    }
    return min
}
Copy the code

3.3 Heap Sort

describe

Heapsort refers to a sort algorithm designed by using heap data structure. Heap is a nearly complete binary tree structure, and also satisfies the property of heap: that is, the key value or index of the child node is always smaller (or larger) than its parent node.

The illustration

code

// TODO
var len;    // Since multiple declared functions require data length, len is set as a global variable
 
function buildMaxHeap(arr) {   // Create a big top heap
    len = arr.length;
    for (var i = Math.floor(len/2); i >= 0; i--) { heapify(arr, i); }}function heapify(arr, i) {     / / heap of adjustment
    var left = 2 * i + 1,
        right = 2 * i + 2,
        largest = i;
 
    if (left < len && arr[left] > arr[largest]) {
        largest = left;
    }
 
    if (right < len && arr[right] > arr[largest]) {
        largest = right;
    }
 
    if (largest != i) {
        swap(arr, i, largest);
        heapify(arr, largest);
    }
}
 
function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
 
function heapSort(arr) {
    buildMaxHeap(arr);
 
    for (var i = arr.length - 1; i > 0; i--) {
        swap(arr, 0, i);
        len--;
        heapify(arr, 0);
    }
    return arr;
}
Copy the code

3.4 Insertion Sort

describe

Insert an unsorted array into an unsorted array, analogous to the process of playing poker

The illustration

code

/* function insertionSort(nums) { for(let i=1; i
      
        0 && num < nums[j]) j-- nums.splice(i, 1) nums.splice(j + 1, 0, num) } return nums } */
      ;>
for(let i=1; i<nums.length; i++) {
    let j = i - 1
    let num = nums[i]
    while(j >= 0 && num < nums[j]) j--
    nums.splice(i, 1)
    nums.splice(j + 1.0, num)
}
return nums
Copy the code

3.5 Shell Sort

1959 Shell invention, the first breakthrough O(N2) sorting algorithm, is an improved version of simple insertion sort. It differs from insertion sort in that it compares distant elements first. Hill sort is also called reduced increment sort.

describe

Insert an upgraded version of sort, first comparing data sets with n/2 intervals, then comparing data sets with N /2/2 intervals, and finally comparing entire arrays

The illustration

code

function shellSort(nums) {
    let len = nums.length, gap = len
    while(gap = getGap(gap)) {
        for(let i=0; i<nums.length; i++) {
            let k = i, num = nums[i]
            while(k - gap >= 0 && num < nums[k - gap]) {
                nums[k] = nums[k - gap] // *
                k = k - gap
            }
            nums[k] = num
        }
    }
}

// Get the increment
function getGap(len) {
    return Math.floor(len/2)}Copy the code

3.6 Merge Sort

describe

Classical divide-and-conquer algorithm, first divided into two heaps, sorted separately, and then combined

The illustration

code

function mergeSort(nums) {
    if (nums.length < 2) return nums
    let i = Math.floor(nums.length / 2)
    return merge(
        mergeSort(nums.slice(0, i)),
        mergeSort(nums.slice(i))
    )
}

// Merge two arrays
function merge(l, r) {
    let res = []
    while(l.length || r.length) {
        if(! l.length || l[0] > r[0]) {
            res.push(r.shift())
        } else if(! r.length || l[0] <= r[0]) {
            res.push(l.shift())
        } else {
            //}}return res
}
Copy the code

3.7 Counting Sort (Counting Sort)

describe

Storing the values of the data as subscripts in a new array and counting them, and then retrieving them, counting sort requires that the input data be integers with a defined range

The illustration

code

function countingSort(nums, max) {
    let ans = []
    let res = new Array(max + 1)
    for(let i=0; i<nums.length; i++) {
        let k = nums[i]
        res[k] = res[k] ? (res[k] + 1) : 1 
    }
    for(let i=0; i<res.length; i++) {
        while (res[i]) {
            ans.push(i)
            res[i] -= 1}}return ans
}
Copy the code

3.8 Bucket Sort

describe

Bucket sort is an updated version of counting sort. It makes use of the mapping relation of functions, and the key of efficiency lies in the determination of the mapping function. Bucket sort works by dividing the data into a finite number of buckets, assuming that the input data is evenly distributed, and sorting each Bucket separately (it is possible to use another sorting algorithm or to continue sorting using Bucket sort recursively).

The illustration

code

function bucketSort(nums) {
    const size = 10
    const [buckets, getHashMap] = HashMap(nums, size)

    for(let i=0; i<nums.length; i++) {
        let idx = getHashMap(nums[i])
        buckets[idx].push(nums[i])
    }

    nums.length = 0
    for(let i=0; i<buckets.length; i++) {
        if (buckets[i].length === 0) continue

        // Insert sort into buckets
        insertionSort(buckets[i])

        for(let j=0; j<buckets[i].length; j++) {
            nums.push(buckets[i][j])
        }
    }

    return nums
}

// Create buckets and mapping functions
function HashMap(nums, size) {
    let max = nums[0]
    let min = nums[0]
    let buckets = new Array(size)

    for(let i=1; i<nums.length; i++) {
        max = max > nums[i] ? max : nums[i]
        min = min < nums[i] ? min : nums[i]
    }
    
    for(let i=0; i<buckets.length; i++) {
        buckets[i] = []
    }

    let pivot = Math.floor((max - min) / size) + 1

    return [buckets, function(num) {
        return Math.floor(num / pivot)
    }]
}

// Insert sort
function insertionSort(nums) {
    for(let i=1; i<nums.length; i++) {
        let j = i - 1
        let num = nums[i]
        while(j > 0 && num < nums[j]) j--
        nums.splice(i, 1)
        nums.splice(j + 1.0, num)
    }
    return nums
}
Copy the code

3.9 Radix Sort

describe

Compare the ones place first, divide and regroup from 0 to 9, then compare the tens place, and then compare

Reference: Radix sort is sorted by low order and then collected; And then sort it in order, and then collect it; And so on, all the way to the highest place. Sometimes some attributes are prioritized, first by low priority, then by high priority. The final order is that the higher-priority ones come first, and the lower-priority ones come first.

The illustration

code

function radixSort(nums) {
    let digit = getMax(nums)
    for(let i=0; i<digit; i++) {
        let newNums = []
        let res = new Array(10).fill(1).map(() = > [])
        for(let j=0; j<nums.length; j++) {
            let level = getNum(nums[j], i)
            res[level].push(nums[j])
        }
        for(let k=0; k<10; k++) {
            while(res[k].length) {
                newNums.push(res[k].shift())
            }
        }
        nums = newNums
    }
    return nums
}

// Get the value of the current bit
function getNum(val, i) {
    return (val % Math.pow(10, i + 1)) / Math.pow(10, i)
}

// Get the maximum number and its bits
function getMax(nums) {
    let max = 0, digit = 0
    for(let i=1; i<nums.length; i++) {
        if (nums[i] > nums[max]) max = i
    }
    max = nums[max]
    digit = (max + ' ').length
    return digit
}
Copy the code

Fourth, front-end TOY version sorting method expansion

function setTimeOutSort(nums) {
    let res = []
    for(num of nums) {
        setTimeOut(() = > res.push(num), num)
    }
    return res
}
Copy the code

Personal notes

1. Why is the best time complexity of select sort and bubble sort different

2. Not proficient in heap sort (TODO), Hill sort and quick sort

3. The analysis of each algorithm is not written