Sorting Algorithms in JS

I. Selection Sort

  • totally unsorted: O(n^2)

  • partially sorted: O(n^2)

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /*
    select min element from rest of unsorted elements, put into front
    - totally unsorted: O(n^2)
    - partially sorted: O(n^2)
    */

    function slectionSort( list ){
    if( list === null || list.length <= 1 ) return

    for( let i = 0; i < list.length; i++ ){
    let curMinId = i
    for( let j = i+1; j < list.length; j++ ){
    list[curMinId] > list[j] && (curMinId = j)
    }
    [ list[i], list[curMinId] ] = [ list[curMinId], list[i] ]
    }
    }

    // Test
    let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ]
    console.log("Original list: " + list)
    slectionSort(list)
    console.log("Selection sort: " + list)

II. Insertion Sort

  • totally unsorted: O(n^2)

  • partially sorted: O(n)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /*
    for each element, insert it into the sorted part exactly before its position
    - totally unsorted: O(n^2)
    - partially sorted: O(n)
    */

    function insertionSort(list){
    if( list === null || list.length <= 1 ) return

    for( let i = 1; i < list.length; i++ ){
    let idToBe = i
    while( idToBe-1 >= 0 && list[idToBe] < list[idToBe-1] ){
    [ list[idToBe-1], list[idToBe] ] = [ list[idToBe], list[idToBe-1] ]
    idToBe -= 1
    }
    }
    }

    // Test
    let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ]
    console.log("Original list: " + list)
    insertionSort(list)
    console.log("Insertion sort: " + list)

III. Bubble Sort

  • BAD version:

    • totally unsorted: O(n^2)

    • partially sorted: O(n^2)

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      /*
      for each element, compare with its right element, swap if it's larger;
      keep doing util (n-1)th, (n-2)th,, (n-3)th ... 1st position
      - totally unsorted: O(n^2)
      - partially sorted: O(n^2)
      */

      function bubbleSort(list){
      if( list === null || list.length <= 1 ) return
      for( let i = list.length-1; i > 0; i-- ){
      for( let k = 0; k < i; k++ ){
      if( list[k] > list[k+1] ){
      [ list[k], list[k+1] ] = [ list[k+1], list[k] ]
      }
      }
      }
      }


      // Test
      let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ]
      console.log("Original list: " + list)
      bubbleSort(list)
      console.log("Bubble sort: " + list)
  • Good Version

    • totally unsorted: O(n^2)

    • partially sorted: O(n) if no swap for a iteration, then every element is in its place, terminate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
for each element, compare with its right element, swap if it's larger;
keep doing util (n-1)th, (n-2)th,, (n-3)th ... 1st position
- totally unsorted: O(n^2)
- partially sorted: O(n)
- if no swap for a iteration, then every element is in its place, terminate
*/

function bubbleSort(list){
if( list === null || list.length <= 1 ) return
let swapped = true
for( let i = list.length-1; i > 0; i-- ){
if(swapped === false) return
swapped = false
for( let k = 0; k < i; k++ ){
if( list[k] > list[k+1] ){
[ list[k], list[k+1] ] = [ list[k+1], list[k] ]
swapped = true
}
}
}
}

// Test
let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ]
console.log("Original list: " + list)
bubbleSort(list)
console.log("Bubble sort: " + list)

VI. Merge Sort

  • Time Complexity

    • totally unsorted: O(n^2)
    • partially sorted: O(n)
  • Space Complexity: cannot sort in-place

    • O(n^2)
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    /*
    recursively divide list into two half, till each half have one or two elements
    recursively merge two half into one, till achieve original size

    Time Complexity
    - totally unsorted: O(n^2)
    - partially sorted: O(n^2)
    Space Complexity:
    - O(n^2)
    */

    function mergeSort(list){
    if( list === null || list.length <= 1 ) return
    return divideAndMerge(list)
    }

    function divideAndMerge(list){
    let l1 = list.slice(0, list.length/2)
    if( l1.length > 1 ) l1 = divideAndMerge(l1)

    let l2 = list.slice(list.length/2, list.length)
    if( l2.length > 1 ) l2 = divideAndMerge(l2)

    return merge(l1, l2)
    }

    function merge(l1, l2){
    let list = []
    let i = 0, j = 0, k = 0
    while(i < l1.length && j < l2.length){
    if( l1[i] > l2[j] )
    list[k++] = l2[j++]
    else
    list[k++] = l1[i++]
    }
    while( i < l1.length ) list[k++] = l1[i++]
    while( j < l2.length ) list[k++] = l2[j++]

    return list
    }

    // Test
    let list = [ 2, 1, 3, 4, 5, 6, 3, 5, 1 ]
    console.log("Original list: " + list)
    mergeSort(list)
    console.log("Merge sort: " + mergeSort(list))

V. Quick Sort

  • Time Complexity:

    • totally unsorted: O(n^2)
    • partially sorted: O(n)
  • Space Complexity: O(n) in-place

  • Approach:

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    /*
    1. randomly choose a pivot, here we use the first element in the question list
    2. loop from both ends, compare value with pivot, and swap their value
    3. how to swap: "LeetCode: sort color" ==> "front & back two ponters"
    https://leetcode.com/problems/sort-colors/description/


    0......0 1......1 x1 x2 .... xm 2.....2
    ^ ^ ^
    zero i two
    smallerToBe largerToBe

    区间一:0 | 区间二:1 | 区间三:未知 | 区间四:2
    */

    function quickSort(list, left, right){
    if( list === null || left >= right ) return

    let pivot = list[left],
    smallerToBe = left,
    largerToBe = right,
    i = left

    while( i <= largerToBe ){
    if( list[i] === pivot ){
    i++
    }else if( list[i] < pivot ){
    swap(list, i++, smallerToBe++)
    }else{
    swap(list, i, largerToBe--)
    }
    }
    quickSort(list, left, smallerToBe-1)
    quickSort(list, largerToBe+1, right)
    }

    function swap(list, p1, p2){ [ list[p1], list[p2] ] = [ list[p2], list[p1] ] }

    // Test
    let list = [ 3, 1, 3, 4, 5, 1, 3, 2, 5, 1 ]
    console.log("Original list: " + list)
    quickSort(list, 0, list.length-1)
    console.log("Quick sort: " + list)