时间空间复杂度 排序是算法中最经典的问题,以下表格对插入排序、冒泡排序、选择排序、希尔排序、快速排序、归并排序这几种排序进行了比较。
排序算法
平均时间复杂度
最坏时间复杂度
空间复杂度
是否稳定
插入排序
O(n2)
O(n2)
O(1)
是
冒泡排序
O(n2)
O(n2)
O(1)
是
选择排序
O(n2)
O(n2)
O(1)
不是
希尔排序
O(nlogn)
O(n2)
O(1)
不是
快速排序
O(nlogn)
O(n2)
O(logn)
不是
归并排序
O(nlogn)
O(nlogn)
O(n)
是
下面是具体的javascript实现:
插入排序 Insertion Sort 插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个形成一个新的、记录数增1的有序表。
插入排序还有升级版-二分插入排序(Binary Sort)。即数据在试图找到自己在前面已排序的部分中的位置时,用比较高效的二分查找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var insertSort = function (arr ) { var len = arr.length , key; for (var i = 1 ; i < len; i++) { var j = i; key = arr[j]; while (--j > -1 ) { if (arr[j] > key) { arr[j + 1 ] = arr[j]; } else { break ; } } arr[j + 1 ] = key; } };
冒泡排序 Bubble Sort 重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序错误就把他们交换过来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var bubbleSort = function (arr ) { var flag = true ; var len = arr.length ; for (var i = 0 ; i < len - 1 ; i++) { flag = true ; for (var j = 0 ; j < len - 1 - i; j++) { if (arr[j] > arr[j + 1 ]) { var temp = arr[j + 1 ]; arr[j + 1 ] = arr[j]; arr[j] = temp; flag = false ; } } if (flag) { break ; } } };
选择排序 Selection Sort 第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var selectSort = function (arr ) { var min; for (var i = 0 ; i < arr.length - 1 ; i++) { min = i; for (var j = i + 1 ; j < arr.length ; j++) { if (arr[min] > arr[j]) { min = j; } } if (i != min) { swap (arr, i, min); } } }; function swap (arr, index1, index2 ) { var temp = arr[index1]; arr[index1] = arr[index2]; arr[index2] = temp; };
希尔排序 Shell Sort 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止
1 2 3 4 5 6 7 8 9 10 11 12 var shellSort = function (arr ) { var gaps = [5 , 3 , 1 ]; for (var g = 0 ; g < gaps.length ; ++g) { for (var i = gaps[g]; i < arr.length ; ++i) { var temp = arr[i]; for (var j = i; j >= gaps[g] && arr[j - gaps[g]] > temp; j -= gaps[g]){ arr[j] = arr[j - gaps[g]]; } arr[j] = temp; } } };
快速排序 Quick Sort 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
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 var quickSort = function (arr, left, right ) { var i, j, t, pivot; if (left >= right) { return ; } pivot = arr[left]; i = left; j = right; while (i != j) { while (arr[j] >= pivot && i < j) { j--; } while (arr[i] <= pivot && i < j) { i++; } if (i < j) { t = arr[i]; arr[i] = arr[j]; arr[j] = t; } } arr[left] = arr[j]; arr[j] = pivot; quickSort (arr, left, i - 1 ); quickSort (arr, i + 1 , right); }
归并排序 Merge Sort 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 47 function mergeSort (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 ; } } 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++; } } }
js 中 Array.prototype.sort 的实现 ECMAScript没有定义使用哪种排序算法,甚至没有规定排序的稳定性,各个浏览器的实现方式也会有所不同。 具体到浏览器中, Mozilla/Firefox : 归并排序 V8 :数组长度小于等于 22 的用二分插入排序,其它的用快速排序(array.js test 源码 ),数组长度大于1000时会 调用 GetThirdIndex
获取更接近中位值的 pivot
见下面注释
1 2 // Quicksort is used for arrays which length > 22 // Arrays which length > 1000 guarantee GetThirdIndex is executed
更新于 20210419,v8的排序算法已变更为 tim-sort
(array-sort.js源码)[https://github.com/v8/v8/blob/master/third_party/v8/builtins/array-sort.tq]
Tim Sort采用分治的思想,分组进行二分插入排序,再用归并排序合并。