JavaScript six kinds of sorting algorithm implementation

The front reading room

This article describes the basic algorithms and advanced data sorting algorithm. These algorithms rely on only the array to store data.

Array Test Platform

First, we construct an array of class test platform

function CArray(numElements) {
    this.dataStore = [];
    this.numElements = numElements;
    this.toString = toString;
    this.clear = clear;
    this.setData = setData;
    this.swap = swap;
}
function setData() {
    for (var i = 0; i < this.numElements; ++i) {
    this.dataStore[i] = Math.floor(Math.random() * (this.numElements + 1));
    }
}
function clear() {
    for (var i = 0; i < this.numElements; ++i) {
    this.dataStore[i] = 0;
    }
}
function toString() {
    var restr = "";
    for (var i = 0; i < this.numElements; ++i) {
    restr += this.dataStore[i] + " ";
    if (i > 0 && i % 10 == 0) {
        restr += "\n";
    }
    }
    return restr;
}
function swap(arr, index1, index2) {
    var temp = arr[index1];
    arr[index1] = arr[index2];
    arr[index2] = temp;
}

Using a test platform category

var numElements = 100;
var myNums = new CArray(numElements);
myNums.setData();
console.log(myNums.toString());

Basic sorting algorithm

These algorithms are very realistic simulation of the human sort the data in real life.

Bubble Sort

It is one of the slowest sorting algorithms, but also one of the most easy to implement sorting algorithms.
It is called bubble sort is because the use of such sorting sorting algorithm, the same data value as the bubbles float from one end to the other end of the array. The assumption is a set of numbers in ascending order, the larger the value to the right float array, while smaller values will float to the left of the array. The reason for this phenomenon is because the algorithm will be moved several times in the array, adjacent data comparison, when the value is greater than the left side value to the right they are interchangeable.

Bubble sort code

function bubbleSort() {
    var numElements = this.dataStore.length;
    for (var outer = numElements; outer >= 2; --outer) {
        for (var inner = 0; inner < outer - 1; ++inner) {
            if (this.dataStore[inner] > this.dataStore[inner + 1]) {
                this.swap(this.dataStore, inner, inner + 1);
            }
        }
    }
}

Sorting process (manual input test data)
avatar
外层循环限定了未排序的范围(从numElements到2),内层循环从左侧的数据开始逐步比较交换,使得未排序范围中最大的数移动到了最右侧,外层排序范围不断缩小,直到还剩两个未排序元素时再比较交换便完成了排序

Selection Sort

选择排序从数组的开头开始,将第一个元素和其他元素进行比较。检查完所有元素后,最小的元素会被放到数组的第一个位置,然后算法会从第二个位置继续。这个过程一直进行,当进行到数组的倒数第二个位置时,所有数据便完成了排序。

function selectionSort() {
    var min;
    for (var outer = 0; outer <= this.dataStore.length - 2; ++outer) {
        min = outer;
        for (var inner = outer + 1; inner <= this.dataStore.length - 1; ++inner) {
            if (this.dataStore[inner] < this.dataStore[min]) {
                min = inner;
            }
        }
        swap(this.dataStore, outer, min);
    }
}

Ordering process
avatar

Insertion Sort

插入排序有两个循环。外循环将数组元素挨个移动,而内循环则对外循环中选中的元素进行比较。如果外循环中选中的元素比内循环中选中的元素小,那么数组元素会向右移动,为内循环中的这个元素腾出位置。

function insertionSort() {
    var temp, inner;
    for (var outer = 1; outer <= this.dataStore.length - 1; ++outer) {
    temp = this.dataStore[outer];
    inner = outer;
    while (inner > 0 && (this.dataStore[inner - 1] >= temp)) {
        this.dataStore[inner] = this.dataStore[inner - 1];
        --inner;
    }
    this.dataStore[inner] = temp;
    }
}

Timing more basic sorting algorithm

10000 random number test

bubbleSort();// 100ms左右
selectionSort();// 50ms左右
insertionSort();// 27ms左右

Select sort and insertion sort faster than bubble sort, insertion sort is the fastest of the three algorithms.

Advanced sorting algorithm

Shell sort

希尔排序在插入排序的基础上做了很大的改善。它会首先比较距离较远的元素,而非相邻的元素。这样可以使离正确位置很远的元素更快地回到合适的位置。当开始用这个算法遍历数据集时,所有元素之间的距离会不断减小,直到处理到数据集的末尾,这时算法比较的就是相邻元素了。希尔排序的工作原理是,通过定义一个间隔序列来表示排序过程中进行比较的元素之间有多远的间隔。我们可以动态定义间隔序列,不过大部分场景算法要用到的间隔序列可以提前定义好。Marchin Ciura spacer sequence defined in a paper published as: 701,301,132,57,23,10,4,1. Here we take a look at how this algorithm is run by a small set of data.
avatar

function shellsort() {
    var temp;
    for (var g = 0; g < this.gaps.length; ++g) {
    for (var i = this.gaps[g]; i < this.dataStore.length; ++i) {
        temp = this.dataStore[i];
        for (var j = i; j >= this.gaps[g] && this.dataStore[j-this.gaps[g]] > temp; j -= this.gaps[g]) {
        this.dataStore[j] = this.dataStore[j - this.gaps[g]];
        }
        this.dataStore[j] = temp;
    }
    }
}

We need to increase the definition of the spacer sequence in CArray class:

this.gaps = [5,3,1];

Calculation of Dynamic spacer sequence

Sedgewick algorithm to determine the initial value of the interval by the following code fragment:

var N = this.dataStore.length;
var h = 1;
while (h < N/3) {
    h = 3 * h + 1;
}

shellsort interval to determine a good value, this function can be defined as before () function runs the same, the only difference is that, back to the last statement before the outer loop will calculate a new value interval:

h = (h-1)/3;

Dynamic calculation interval ordered sequence Hill

function shellsort1() {
    var N = this.dataStore.length;
    var h = 1;
    while (h < N/3) {
        h = 3 * h + 1;
    }
    while (h >= 1) {
        for (var i = h; i < N; i ++) {
            for (var j = i; j >= h && this.dataStore[j] < this.dataStore[j-h]; j -= h) {
                this.swap(this.dataStore, j, j - h);
            }
        }
        h = (h-1)/3;
    }
}

For ordering 10,000 random tests:

myNums.shellsort(); // 20ms左右
myNums.shellsort1(); // 8ms左右

Merge sort

归并排序把一系列排好序的子序列合并成一个大的完整有序序列。我们需要两个排好序的子数组,然后通过比较数据大小,从最小的数据开始插入,最后合并得到第三个数组。然而,在实际情况中,归并排序还有一些问题,我们需要更大的空间来合并存储两个子数组。

Merge sort of bottom-up self
Generally, merge sort will be implemented using a recursive algorithm. However, in JavaScript in this way is not feasible, because the recursion depth too deep. So, we use a non-recursive way to implement this algorithm, this strategy is called bottom-up merge sort.
The algorithm first data set is decomposed into a set of only one element of the array. Then by creating a set of left and right sub-array will slowly merge them together, each part of the merger will save the data sorted, all the data until the last remaining perfect this array are sorted.
avatar
Algorithm code

function mergeSort() {
    var arr = this.dataStore;
    if (arr.length < 2) {
    return;
    }
    var step = 1;
    var left, right;
    while (step < arr.length) {
    left = 0;
    right = step;
    while (right + step <= arr.length) {
        this.mergeArrays(arr, left, left+step, right, right+step);
        left = right + step;
        right = left + step;
    }
    if (right < arr.length) {
        this.mergeArrays(arr, left, left+step, right, arr.length);
    }
    step *= 2;
    }
}

function mergeArrays(arr, startLeft, stopLeft, startRight, stopRight) {
    var rightArr = new Array(stopRight - startRight + 1);
    var leftArr = new Array(stopLeft - startLeft + 1);
    k = startRight;
    for (var i = 0; i < (rightArr.length-1); ++i) {
    rightArr[i] = arr[k];
    ++k;
    }
    k = startLeft;
    for (var i = 0; i < (leftArr.length-1); ++i) {
    leftArr[i] = arr[k];
    ++k;
    }
    rightArr[rightArr.length - 1] = Infinity;
    leftArr[leftArr.length - 1] = Infinity;
    var m = 0;
    var n = 0;
    for (var k = startLeft; k < stopRight; ++k) {
    if (leftArr[m] <= rightArr[n]) {
        arr[k] = leftArr[m];
        m++;
    } else {
        arr[k] = rightArr[n];
        n++;
    }
    }
}

Quick Sort

快速排序是处理大数据集最快的排序算法之一。它是一种分而治之的算法,通过递归的方法将数据依次分解为包含较小元素和较大元素的不同子序列。该算法不断重复这个步骤直到所有数据都是有序的。
这个算法首先要在列表中选择一个元素作为基准值(pivot)。数据排序围绕基准值进行,将列表中小于基准值的元素移到数组的底部,将大于基准值的元素移到数组的顶部。
avatar

Pseudo-code algorithm

  1. Selecting a reference element, will be divided into two sub-sequences listing
  2. Reorder the list, all of the elements than the reference value on the front of the reference value, all the elements on the back worth than the reference value of the reference
  3. Sequences sequences respectively smaller and larger elements elements Repeat steps 1 and 2
    the following procedures:
function qSort(list) {
    var list;
    if (list.length == 0) {
        return [];
    }
    var lesser = [];
    var greater = [];
    var pivot = list[0];
    for (var i = 1; i < list.length; i ++) {
        if (list[i] < pivot) {
        lesser.push(list[i]);
        } else {
        greater.push(list[i]);
        }
    }
    return this.qSort(lesser).concat(pivot, this.qSort(greater));
}

In qSort output sorting process before the function returns

console.log(lesser.concat(pivot, greater).toString());

avatar
10000 random numbers sorting test

qSort(); // 17ms左右

Quick sort algorithm is very suitable for large data sets; but performance will decrease when dealing with small data sets.

(Attached) test platform code

<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
  <script>
    function CArray(numElements) {
      // this.dataStore = [72, 54, 58, 30, 31, 78, 2, 77, 82, 72];
      this.dataStore = [];
      // this.dataStore = [44, 75, 23, 43, 55, 12, 64, 77 ,33];
      this.numElements = numElements;
      this.toString = toString;
      this.clear = clear;
      this.setData = setData;
      this.swap = swap;
      this.bubbleSort = bubbleSort;
      this.selectionSort = selectionSort;
      this.insertionSort = insertionSort;
      this.shellsort = shellsort;
      this.shellsort1 = shellsort1;
      this.mergeSort = mergeSort;
      this.mergeArrays = mergeArrays;
      this.qSort = qSort;
      this.gaps = [5, 3, 1];
    }
    function setData() {
      for (var i = 0; i < this.numElements; ++i) {
        this.dataStore[i] = Math.floor(Math.random() * (this.numElements + 1));
      }
    }
    function clear() {
      for (var i = 0; i < this.numElements; ++i) {
        this.dataStore[i] = 0;
      }
    }
    function toString() {
      var restr = "";
      for (var i = 0; i < this.numElements; ++i) {
        restr += this.dataStore[i] + " ";
        if (i > 0 && i % 10 == 0) {
          restr += "\n";
        }
      }
      return restr;
    }
    function swap(arr, index1, index2) {
      var temp = arr[index1];
      arr[index1] = arr[index2];
      arr[index2] = temp;
    }
    function selectionSort() {
        var min;
        for (var outer = 0; outer <= this.dataStore.length - 2; ++outer) {
            min = outer;
            for (var inner = outer + 1; inner <= this.dataStore.length - 1; ++inner) {
                if (this.dataStore[inner] < this.dataStore[min]) {
                    min = inner;
                }
            }
            swap(this.dataStore, outer, min);
        }
    }
    function bubbleSort() {
        var numElements = this.dataStore.length;
        for (var outer = numElements; outer >= 2; --outer) {
            for (var inner = 0; inner < outer - 1; ++inner) {
                if (this.dataStore[inner] > this.dataStore[inner + 1]) {
                    this.swap(this.dataStore, inner, inner + 1);
                }
            }
        }
    }
    function insertionSort() {
      var temp, inner;
      for (var outer = 1; outer <= this.dataStore.length - 1; ++outer) {
        temp = this.dataStore[outer];
        inner = outer;
        while (inner > 0 && (this.dataStore[inner - 1] >= temp)) {
          this.dataStore[inner] = this.dataStore[inner - 1];
          --inner;
        }
        this.dataStore[inner] = temp;
      }
    }
    function shellsort() {
      var temp;
      for (var g = 0; g < this.gaps.length; ++g) {
        for (var i = this.gaps[g]; i < this.dataStore.length; ++i) {
          temp = this.dataStore[i];
          for (var j = i; j >= this.gaps[g] && this.dataStore[j-this.gaps[g]] > temp; j -= this.gaps[g]) {
            this.dataStore[j] = this.dataStore[j - this.gaps[g]];
          }
          this.dataStore[j] = temp;
        }
      }
    }
    function shellsort1() {
      var N = this.dataStore.length;
      var h = 1;
      while (h < N/3) {
          h = 3 * h + 1;
      }
      while (h >= 1) {
          for (var i = h; i < N; i ++) {
              for (var j = i; j >= h && this.dataStore[j] < this.dataStore[j-h]; j -= h) {
                  this.swap(this.dataStore, j, j - h);
              }
          }
          h = (h-1)/3;
      }
    }
    function mergeSort() {
      var arr = this.dataStore;
      if (arr.length < 2) {
        return;
      }
      var step = 1;
      var left, right;
      while (step < arr.length) {
        left = 0;
        right = step;
        while (right + step <= arr.length) {
          this.mergeArrays(arr, left, left+step, right, right+step);
          left = right + step;
          right = left + step;
        }
        if (right < arr.length) {
          this.mergeArrays(arr, left, left+step, right, arr.length);
        }
        step *= 2;
      }
    }
    function mergeArrays(arr, startLeft, stopLeft, startRight, stopRight) {
      var rightArr = new Array(stopRight - startRight + 1);
      var leftArr = new Array(stopLeft - startLeft + 1);
      k = startRight;
      for (var i = 0; i < (rightArr.length-1); ++i) {
        rightArr[i] = arr[k];
        ++k;
      }
      k = startLeft;
      for (var i = 0; i < (leftArr.length-1); ++i) {
        leftArr[i] = arr[k];
        ++k;
      }
      rightArr[rightArr.length - 1] = Infinity;
      leftArr[leftArr.length - 1] = Infinity;
      var m = 0;
      var n = 0;
      for (var k = startLeft; k < stopRight; ++k) {
        if (leftArr[m] <= rightArr[n]) {
          arr[k] = leftArr[m];
          m++;
        } else {
          arr[k] = rightArr[n];
          n++;
        }
      }
    }
    function qSort(list) {
        var list;
        if (list.length == 0) {
            return [];
        }
        var lesser = [];
        var greater = [];
        var pivot = list[0];
        for (var i = 1; i < list.length; i ++) {
          if (list[i] < pivot) {
            lesser.push(list[i]);
          } else {
            greater.push(list[i]);
          }
        }
        return this.qSort(lesser).concat(pivot, this.qSort(greater));
    }
    var numElements = 200000;
    var myNums = new CArray(numElements);
    myNums.setData();
    // console.log(myNums.toString());
    var startTime = new Date().getTime();
    // myNums.insertionSort();// 27ms左右
    // myNums.bubbleSort();// 100ms左右
    // myNums.selectionSort();// 50ms左右
    // myNums.shellsort(); // 20ms左右
    // myNums.shellsort1(); // 8ms左右
    // myNums.mergeSort(); // 9ms左右
    myNums.dataStore = myNums.qSort(myNums.dataStore); // 17ms左右
    var endTime = new Date().getTime();
    console.log('耗时: ' + (endTime - startTime) + '毫秒');
    // console.log(myNums.toString());
    
  </script>
</body>
</html>

reference

  1. "JavaScript data structures and algorithms described in"

The front reading room

Guess you like

Origin www.cnblogs.com/fe-read/p/11783541.html