Ten sorting javascript implementation + animation demonstration

Posted by bandit on Wed, 05 Jan 2022 01:38:06 +0100

Algorithm classification

  1. Comparison sort: the relative order between elements is determined by comparison. Because its time complexity cannot exceed O(nlogn), it is also called nonlinear time comparison sort.
  2. Non comparison sort: it does not determine the relative order between elements through comparison. It can break through the time lower bound based on comparison sort and run in linear time. Therefore, it is also called linear time non comparison sort.

Algorithm complexity


Related concepts

  1. Stable: if a was in front of b and a=b, a will still be in front of b after sorting.
  2. Unstable: if a was originally in front of b and a=b, a may appear after b after sorting.
  3. Time complexity: the total number of operations on sorting data. Reflect the law of operation times when n changes.
  4. Spatial complexity: refers to the algorithm in the computer

Comparison class sorting

Bubble sorting

Bubble sorting is one of the basic sorting algorithms. Its idea is to compare two adjacent elements. The larger number rises and the smaller number sinks. In this way, the maximum value will be arranged at one end after one comparison. The whole process is like bubbles, so it is called bubble sorting.

Usage scenario: bubble sorting is applicable to sorting scenarios with small amount of data, because the implementation method of bubble sorting is relatively simple.
Algorithm description:

  • Compare adjacent elements. If the first one is bigger than the second, exchange them
  • Do the same for each pair of adjacent elements, from the first pair at the beginning to the last pair at the end, so that the last element should be the largest number
  • Repeat the above steps for all elements except the last one
  • Repeat steps 1 to 3 until the sorting is completed

Animation demonstration

code implementation

let bubblearr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
function bubbleSort(arr) {
    let i = arr.length, j;
    let maxnum;
    while (i > 0) {
        for (j = 0; j < i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // A new way
                // maxnum = arr[j];
                // arr[j] = arr[j + 1];
                // arr[j + 1] = maxnum;
                //Deconstruction replacement
                [arr[j + 1], arr[j]] = [arr[j], arr[j + 1]]
            }
        }
        i--;
    }
    return arr;
}
console.log(bubbleSort(bubblearr), 'Bubble sorting')

Select sort

Selective sorting is a simple and intuitive sorting algorithm. Its working principle is: select the smallest (or largest) element from the data elements to be sorted for the first time, store it in the starting position of the sequence, then find the smallest (large) element from the remaining unordered elements, continue to put it in the starting position, and know that the number of unordered elements is 0.

Usage scenario: when the number of elements in the sequence to be sorted is small.
Algorithm description: the direct selection sorting of n records can get ordered results through n-1 times of direct selection sorting. The specific algorithm is described as follows:

  • Initial state: the disordered area is R[1... n], and the ordered area is empty
  • At the beginning of the ith sort (i=1,2,3... n-1), the current ordered area and disordered area are R[1... i-1] and R(i... n) respectively. This sequence selects the record R[k] with the smallest keyword from the current unordered area and exchanges it with the first record r in the unordered area, so that R[1... I] and R[i+1... n) become a new ordered area with an increase in the number of records and a new unordered area with a decrease in the number of records, respectively
  • At the end of the n-1 pass, the array is ordered

Animation demonstration

code implementation

let selectarr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
function selectSort(arr) {
    let minnum;
    for (let i = 0; i < arr.length; i++) {
        minnum = i; // Get the current value and compare it with the following values
        for (let k = i; k < arr.length; k++) {
            if (arr[minnum] > arr[k]) {
                minnum = k;
            }
        }
        if (minnum !== i) {// If the minimum value is not the current value, it is interchangeable
            [arr[i], arr[minnum]] = [arr[minnum], arr[i]]
        }
    }
    return arr
}
console.log(selectSort(selectarr), 'Select sort')

Insert sort

The algorithm description of insertion sort is a simple and intuitive sorting algorithm. Its working principle is to build an ordered sequence, scan the unordered data from back to front in the sorted sequence, find the corresponding position and insert it.

Usage scenario: the number of elements in the sequence to be sorted is small (< = 50), and the elements are basically ordered.
Algorithm description: the steps of insertion sorting are as follows: take out one element from the unordered part each time, compare it with the elements in the ordered part from back to front, find the appropriate position, and insert the element into the ordered group. The specific algorithm is described as follows:

  • Starting with the first element, the element can be considered to have been sorted
  • Take out the next element and scan from back to forward in the sorted element sequence
  • If the element (sorted) is larger than the new element, move the element to the next position
  • Repeat step 3 until you find a location where the sorted element is less than or equal to the new element
  • After inserting the new element into this location
  • Repeat steps 2 to 5

Animation demonstration

code implementation

let insertionarr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
function insertionSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        console.time('Insert sort time:');
        for (let i = 1; i < array.length; i++) {
            let key = array[i];
            let j = i - 1;
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j--;
            }
            array[j + 1] = key;
        }
        console.timeEnd('Insert sort time:');
        return array;
    } else {
        return 'array is not an Array!';
    }
}
console.log(insertionSort(insertionarr), 'Insert sort')

Quick sort

Basic idea of quick sorting: select a benchmark value during each sorting, then compare all elements with the benchmark value, divide them into left and right piles according to size, and then recursively execute the process until all elements are sorted.

Usage scenario: there are many elements in the sequence to be sorted, and the elements are out of order.
Algorithm description: quick sorting uses divide and conquer to divide a list into two sub lists. The specific algorithm is described as follows:

  • Picking out an element from a sequence is called a "pivot"
  • Reorder the sequence. All elements smaller than the benchmark value are placed in front of the benchmark, and all elements larger than the benchmark value are placed behind the benchmark (the same number can be on either side). After the partition exits, the benchmark is in the middle of the sequence. This is called a partition operation
  • Recursively sorts subsequences that are smaller than the reference value element and subsequences that are larger than the reference value element

Animation demonstration

code implementation

let celerityarr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
function celeritySort(arr) {
    if (arr.length <= 1) {
        return arr
    }
    let Snum = Math.floor(arr.length / 2);
    let sZnum = arr.splice(Snum, 1)[0];//Median number
    let left = [];//Left
    let right = [];//Right part
    for (let i = 0; i < arr.length; i++) {
        if (sZnum < arr[i]) {// You can change the sort increment and decrement
            right.push(arr[i])
        } else {
            left.push(arr[i])
        }
    }
    //concat merge array left plus middle plus right
    return celeritySort(left).concat([sZnum], celeritySort(right))
}
console.log(celeritySort(celerityarr), 'Quick sort')

Shell Sort

In 1959, Shell invented the first sorting algorithm to break through O(n2), which is an improved version of simple insertion sorting. It differs from insert sort in that it preferentially compares elements that are far away. Hill sort is also called reduced incremental sort.

Usage scenario: when there are few sequence elements to be sorted.
Algorithm description:
First, divide the whole record sequence to be sorted into several subsequences for direct insertion sorting. The specific algorithm description is as follows:

  • Select an incremental sequence t1, t2,..., tk, where ti > TJ, tk=1
  • Sort the sequence k times according to the number of incremental sequences k
  • For each sorting, the sequence to be sorted is divided into several subsequences with length m according to the corresponding increment ti, and each sub table is directly inserted and sorted. Only when the increment factor is 1, the whole sequence is treated as a table, and the table length is the length of the whole sequence

Animation demonstration

code implementation

let shellarr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
function shellSort(arr) {
   //Gradually reduce the step size until it is 1
   for (let i = Math.floor(arr.length / 2); i > 0; i = Math.floor(i / 2)) {
       //The arrays are grouped according to the step size, and the insertion sorting method is used for exchange sorting
       //Insert sort from the set of data with incremental size
       for (let atom = i; atom < arr.length; atom++) {
           //atom-i represents the elements adjacent to the next door in the same group as the element. For the elements in the same group, insert sorting is performed
           if (arr[atom - i] > arr[atom]) {//Judge size
               [arr[atom - i], arr[atom]] = [arr[atom], arr[atom - i]]
           }
       }
   }
   return arr
}
console.log(shellSort(shellarr), 'Shell Sort ')

Merge sort

Merge sort is an effective sort algorithm based on merge operation. The algorithm is a very typical application of Divide and Conquer. The ordered subsequences are combined to obtain a completely ordered sequence; That is, each subsequence is ordered first, and then the subsequence segments are ordered. If two ordered tables are merged into one ordered table, it is called 2-way merging.

Usage scenario: large amount of data and stability requirements. The cost is the need for additional memory space.
Algorithm description:

  • The input sequence with length n is divided into two subsequences with length n/2
  • The two subsequences are sorted by merging
  • Merge two sorted subsequences into a final sorting sequence

Animation demonstration

code implementation

let mergearr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
function mergeSort(arr) {
    if (arr.length < 2) {
        return arr
    }
    let middle = Math.floor(arr.length / 2)
    //Split into two subarrays
    let left = arr.slice(0, middle)
    let right = arr.slice(middle)
    //recursive partitioning 
    let mergeSortLeft = mergeSort(left)
    let mergeSortRight = mergeSort(right)
    //Merge comparison
    return merge(mergeSortLeft, mergeSortRight);
}
function merge(left, right) {
    // After comparison, push to the new array
    const result = [];
    while (left.length && right.length) {
        // Note: the judgment condition is less than or equal to. If it is only less than, the sorting will be unstable
        //Each time, delete the first element of left or right and add it to the result
        if (left[0] <= right[0]) result.push(left.shift());
        else result.push(right.shift());
    }
    //Add the remaining elements
    while (left.length) result.push(left.shift());
    while (right.length) result.push(right.shift());
    return result;
};
console.log(mergeSort(mergearr), 'Merge sort')

Heap sort

Heap sort is a sort algorithm designed by using the data structure of heap. Heap is a structure similar to a complete binary tree and satisfies the nature of heap: that is, the key value or index of a child node is always less than (or greater than) its parent node.

Algorithm description:

  • Build the initial keyword sequence to be sorted (R1,R2,... Rn) into a large top heap, which is the initial unordered area
  • Exchange the top element R[1] with the last element R[n]. At this time, a new disordered region (R1,R2,... Rn-1) and a new ordered region (Rn) are obtained, and R[1,2... N-1] < = R[n]
  • Since the new heap top R[1] may violate the nature of the heap after exchange, it is necessary to adjust the current unordered area (R1,R2,... Rn-1) to a new heap, and then exchange R[1] with the last element of the unordered area again to obtain a new unordered area (R1,R2,... Rn-2) and a new ordered area (Rn-1,Rn). Repeat this process until the number of elements in the ordered area is n-1, and the whole sorting process is completed

Animation demonstration

code implementation

let heaparr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
let len;    // Because multiple functions declared need data length, set len as a global variable
function buildMaxHeap(arr) { // Build large top reactor
    len = arr.length;
    for (let i = Math.floor(len / 2); i >= 0; i--) {
        heapify(arr, i);
    }
}
function heapify(arr, i) { // Heap adjustment
    let 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) {// Each time the maximum value is separated from the stack, adjust the relationship between the upper and lower layers
        [arr[i], arr[largest]] = [arr[largest], arr[i]];
        heapify(arr, largest);
    }
}
function heapSort(arr) {
    buildMaxHeap(arr); // Build large top reactor
    for (let i = arr.length - 1; i >= 0; i--) {
        [arr[i], arr[0]] = [arr[0], arr[i]]
        len--;
        heapify(arr, 0);// Find the largest and put it last len--
    }
    return arr;
}
console.log(heapSort(heaparr), 'Heap sort')

Non comparison sort

Count sort

Counting sort is not a sort algorithm based on comparison. Its core is to convert the input data values into keys and store them in the additional array space. As a sort with linear time complexity, count sort requires that the input data must be integers with a certain range.

Algorithm description:

  • Find the largest and smallest elements in the array to be sorted
  • Count the number of occurrences of each element with value i in the array and store it in the ith item of array C
  • All counts are accumulated (starting from the first element in C, and each item is added to the previous item)
  • Reverse fill the target array: put each element i in item C(i) of the new array, and subtract 1 from C(i) for each element

Animation demonstration

code implementation

let countingarr = [3, 2, 4, 9, 1, 5, 7, 6, 8, 1, 8, 1];
function countingSort(arr, maxValue) {
    let bucket = new Array(maxValue + 1),
        sortedIndex = 0;
    for (let i = 0; i < arr.length; i++) {// count
        if (!bucket[arr[i]]) bucket[arr[i]] = 0;// The initial value is not set
        bucket[arr[i]]++;// Self increasing
    }
    for (let j = 0; j <= maxValue; j++) {
        while (bucket[j] > 0) {// Rewrite arr sort
            arr[sortedIndex++] = j;
            bucket[j]--;
        }
    }
    return arr;
}
console.log(countingSort(countingarr, 9), 'Count sort')// Pass array and maximum value in array

Bucket sorting

Bucket sorting is an upgraded version of counting sorting. It makes use of the mapping relationship of the function. The key to efficiency lies in the determination of the mapping function. Working principle of bucket sort: assuming that the input data is uniformly distributed, divide the data into a limited number of buckets, and sort each bucket separately (it is possible to use another sorting algorithm or continue to use bucket sorting recursively).

Algorithm description:

  • Set a quantitative array as an empty bucket
  • Traverse the input data and put the data into the corresponding bucket one by one
  • Sort each bucket that is not empty
  • Splice the ordered data from a bucket that is not empty.

Animation demonstration

code implementation

let bucketarr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
function bucketSort(arr, bucketSize) {
    if (arr.length === 0) {
        return arr;
    }
    let i, minValue = arr[0], maxValue = arr[0];
    for (i = 1; i < arr.length; i++) {// Loop to find the minimum and maximum values
        if (arr[i] < minValue) minValue = arr[i];  // Minimum value of input data
        else if (arr[i] > maxValue) maxValue = arr[i];  // Maximum value of input data
    }
    // Initialization of bucket
    let DEFAULT_BUCKET_SIZE = 5;  // Set the default number of buckets to 5
    bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
    let bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
    let buckets = new Array(bucketCount);
    for (i = 0; i < buckets.length; i++) buckets[i] = [];// buckets programming two-dimensional array
    // The mapping function is used to allocate the data to each bucket
    for (i = 0; i < arr.length; i++) {// Put the values in the array into the created bucket
        buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
    }
    arr.length = 0;// Empty array
    for (i = 0; i < buckets.length; i++) {
        insertionSort(buckets[i]); // Sort each bucket. Insert sort is used here
        for (let j = 0; j < buckets[i].length; j++) {
            arr.push(buckets[i][j]);// Add the sorted to the array in turn
        }
    }
    return arr;
}
console.log(bucketSort(bucketarr), 'Bucket sorting')

Cardinality sort

Cardinality sorting is sorting according to the low order, and then collecting; Then sort according to the high order, and then collect; And so on until the highest order. Sometimes some attributes are prioritized. They are sorted first by low priority and then by high priority. The final order is the high priority, the high priority, the same high priority, and the low priority, the high priority.

Algorithm description:

  • Gets the maximum number in the array and the number of bits
  • arr is the original array, and each bit is taken from the lowest bit to form a radix array
  • Count and sort the radix (using the characteristics that count sorting is suitable for a small range of numbers)

Animation demonstration

code implementation

let radixarr = [3, 2, 1, 5, 7, 6, 8, 21, 42, 31, 83, 62, 58, 51];
function radixSort(arr, maxDigit) {
    let counter = [];
    let mod = 10;
    let dev = 1;
    for (let i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
        for (let j = 0; j < arr.length; j++) {
            let bucket = parseInt((arr[j] % mod) / dev);
            if (counter[bucket] == null) {// Convert it to a two-dimensional array
                counter[bucket] = [];
            }
            counter[bucket].push(arr[j]);// push to the corresponding cardinality
        }
        let pos = 0;
        for (let j = 0; j < counter.length; j++) {
            let value = null;
            if (counter[j] != null) {
                while ((value = counter[j].shift()) != null) {
                    arr[pos++] = value;// Refactoring array
                }
            }
        }
    }
    return arr;
}
console.log(radixSort(radixarr, 2), 'Cardinality sort')// The pass array and the maximum number of digits 83 are two digits, so it is 2

Maybe the code is not the best, because it is written by my understanding and reference
reference resources: Ten classical sorting algorithms

Topics: Javascript Front-end ECMAScript