[js] 几种排序算法以及性能比较
冒泡排序
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
var testArray = [], start = 0, end = 0, consume = 0; for (var i = 0; i < 20000; ++i) { testArray[i] = Math.floor((Math.random() * 1000) + 1); } //console.info(testArray); function bubbleSort(arr) { //console.warn(arr); var numElements = arr.length, temp; for (var outer = numElements; outer > 1; --outer) { for (var inner = 0; inner < outer; ++inner) { if (arr[inner] > arr[inner + 1]) { temp = arr[inner]; arr[inner] = arr[inner + 1]; arr[inner + 1] = temp; } //console.log(arr); } //console.error(arr); } //console.info(arr); return arr; } start = Date.now(); bubbleSort(testArray); end = Date.now(); consume = end - start; //console.log(testArray); //会改变原数组 console.log('bubbleSort:' + consume); //20000数量数组消耗时间为:2125-2145 ms
//稍微优雅一点的写法 function bubble(a) { let arr = a; let l = arr.length; while (l) { for (let j = 0; j < l; j++) { let left = arr[j]; let right = arr[j + 1]; if (left > right) { arr[j] = right; arr[j + 1] = left; } } l--; } return arr; } console.error(bubble([8, 7, 6, 5, 4, 3, 2, 1]));
选择排序
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
var testArray = [], start = 0, end = 0, consume = 0; for (var i = 0; i < 20000; ++i) { testArray[i] = Math.floor((Math.random() * 1000) + 1); } // for (var i = 0; i < 5; ++i) { // testArray[i] = Math.floor((Math.random() * 100) + 1); // } //console.info(testArray); function selectionSort(arr) { //console.warn(arr); var min, temp; for (var outer = 0; outer < arr.length - 1; ++outer) { min = outer; for (var inner = outer + 1; inner < arr.length; ++inner) { if (arr[inner] < arr[min]) { min = inner; } } temp = arr[outer]; arr[outer] = arr[min]; arr[min] = temp; //console.log(arr); } //console.info(arr); return arr; } start = Date.now(); selectionSort(testArray); end = Date.now(); consume = end - start; //console.log(testArray); //会改变原数组 console.log('selectionSort:' + consume); //20000数量数组消耗时间为:420-430 ms
插入排序
每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
var testArray = [], start = 0, end = 0, consume = 0; for (var i = 0; i < 20000; ++i) { testArray[i] = Math.floor((Math.random() * 1000) + 1); } // for (var i = 0; i < 5; ++i) { // testArray[i] = Math.floor((Math.random() * 100) + 1); // } //console.info(testArray); function insertionSort(arr) { //console.warn(arr); var temp, inner; for (var outer = 1; outer <= arr.length - 1; ++outer) { temp = arr[outer]; inner = outer; while (inner > 0 && (arr[inner - 1] >= temp)) { arr[inner] = arr[inner - 1]; --inner; } arr[inner] = temp; //console.log(arr); } //console.info(arr); return arr; } start = Date.now(); insertionSort(testArray); end = Date.now(); consume = end - start; //console.log(testArray); //会改变原数组 console.log('insertionSort:' + consume); //20000数量数组消耗时间为:180-195 ms
希尔排序
是直接插入排序算法的一种更高效的改进版本。
#自定义间隔
var testArray = [], start = 0, end = 0, consume = 0; // for (var i = 0; i < 20000; ++i) { // testArray[i] = Math.floor((Math.random() * 1000) + 1); // } for (var i = 0; i < 5; ++i) { testArray[i] = Math.floor((Math.random() * 100) + 1); } //console.info(testArray); function shellsort(arr) { //console.warn(arr); var gaps = [5, 3, 1]; for (var g = 0; g < gaps.length; ++g) { for (var i = gaps[g]; i < testArray.length; ++i) { var temp = testArray[i]; for (var j = i; j >= gaps[g] && testArray[j - gaps[g]] > temp; j -= gaps[g]) { testArray[j] = testArray[j - gaps[g]]; //console.info(arr); } testArray[j] = temp; //console.log(arr); } //console.error(arr); } //console.warn(arr); return arr; } start = Date.now(); shellsort(testArray); end = Date.now(); consume = end - start; //console.log(testArray); //会改变原数组 console.log('shellsort:' + consume);
#动态间隔
var testArray = [], start = 0, end = 0, consume = 0; for (var i = 0; i < 20000; ++i) { testArray[i] = Math.floor((Math.random() * 1000) + 1); } // for (var i = 0; i < 5; ++i) { // testArray[i] = Math.floor((Math.random() * 100) + 1); // } //console.info(testArray); function shellsort(arr) { //console.warn(arr); var N = arr.length, h = 1, temp; while (h < N / 3) { h = 3 * h + 1; } while (h >= 1) { for (var i = h; i < N; i++) { for (var j = i; j >= h && arr[j] < arr[j - h]; j -= h) { temp = arr[j]; arr[j] = arr[j - h]; arr[j - h] = temp; } } h = (h - 1) / 3; } //console.log(arr); return arr; } start = Date.now(); shellsort(testArray); end = Date.now(); consume = end - start; //console.log(testArray); //会改变原数组 console.log('shellsort:' + consume); //20000数量数组消耗时间为:10ms左右
归并排序
将两个顺序序列合并成一个顺序序列的方法。
#自底向上的归并排序
var testArray = [], start = 0, end = 0, consume = 0; for (var i = 0; i < 20000; ++i) { testArray[i] = Math.floor((Math.random() * 1000) + 1); } // for (var i = 0; i < 5; ++i) { // testArray[i] = Math.floor((Math.random() * 100) + 1); // } //console.info(testArray); function mergeSort(arr) { //console.warn(arr); if (arr.length < 2) { return; } var step = 1; var left, right; while (step < arr.length) { left = 0; right = step; while (right + step <= arr.length) { mergeArrays(arr, left, left + step, right, right + step); left = right + step; right = left + step; } if (right < arr.length) { mergeArrays(arr, left, left + step, right, arr.length); } step *= 2; } //console.log(arr); return arr; } 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; // a sentinel value leftArr[leftArr.length - 1] = Infinity; // a sentinel value 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++; } } //console.info("left array - ", leftArr); //console.info("right array - ", rightArr); } start = Date.now(); mergeSort(testArray); end = Date.now(); consume = end - start; //console.log(testArray); //会改变原数组 console.log('mergeSort:' + consume); //20000数量数组消耗时间为:10-20ms
快速排序
首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。
var testArray = [], start = 0, end = 0, consume = 0; for (var i = 0; i < 20000; ++i) { testArray[i] = Math.floor((Math.random() * 1000) + 1); } // for (var i = 0; i < 5; ++i) { // testArray[i] = Math.floor((Math.random() * 100) + 1); // } //console.info(testArray); function quickSort(arr) { //console.warn(arr); if (arr.length == 0) { return []; } var left = []; var right = []; var pivot = arr[0]; for (var i = 1; i < arr.length; i++) { //console.info('基准值:' + pivot + ' 当前元素' + arr[i]); if (arr[i] < pivot) { //console.error('移动:' + arr[i] + ' 到左边'); left.push(arr[i]); } else { //console.error('移动:' + arr[i] + ' 到右边'); right.push(arr[i]); } } return quickSort(left).concat(pivot, quickSort(right)); } start = Date.now(); quickSort(testArray); //console.log(quickSort(testArray)); end = Date.now(); consume = end - start; //console.log(testArray); //会改变原数组 console.log('quickSort:' + consume); //20000数量数组消耗时间为:50-60ms
sort()排序
var testArray = [], start = 0, end = 0, consume = 0; for (var i = 0; i < 20000; ++i) { testArray[i] = Math.floor((Math.random() * 1000) + 1); } start = Date.now(); testArray.sort(); //console.log(quickSort(testArray)); end = Date.now(); consume = end - start; //console.log(testArray); //会改变原数组 console.log('Sort:' + consume); //20000数量数组消耗时间为:20-30ms