算法:基于比较的排序算法
最近整理了常用的排序算法,整理好,留下自己的思考过程。
1、冒泡排序:
(1)平均时间复杂度:O(n2)
(2)最好时间复杂度:O(n)
(3)最坏时间复杂度:O(n2)
(5)空间复杂度:O(1)
(5)稳定性:稳定
(6)JavaScript实现:
function bubble ( arr ) { var len = arr.length; var tmp; // 外层循环负责控制排序的趟数 for(var i = 0; i < len - 1; i++){ // 内层循环负责进行一趟排序 for(var j = 0; j < len - 1 - i; j++){ if(arr[j + 1] < arr[j]){ tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; }; }; }; return arr; };
2、选择排序:
(1)平均时间复杂度:O(n2)
(2)最好时间复杂度:O(n2)
(3)最坏时间复杂度:O(n2)
(4)空间复杂度:O(1)
(5)稳定性:不稳定
(6)JavaScript实现:
function select( arr ) { var len = arr.length; // 外层循环需要进行len - 1趟排序 for(var i = 0; i < len - 1; i++){ var index = i; var min = arr[i]; var tmp; // 内层循环从未排序的数组元素中比较出最小的一个 for(var j = i + 1; j < len; j++){ if(min > arr[j]){ index = j; min = arr[j]; }; }; // 将其放在排序后的数组元素的最后 tmp = arr[i]; arr[i] = min; arr[index] = tmp; }; };
3、插入排序:
(1)平均时间复杂度:O(n2)
(2)最好时间复杂度:O(n)
(3)平均时间复杂度:O(n2)
(4)空间复杂度:O(1)
(5)稳定性:稳定
(6)JavaScript实现:
function insert ( arr ) { var len = arr.length; var tmp; for(var i = 1; i < len; i++){ // 取出当前的数组元素 tmp = arr[i]; for(var j = i - 1; j >= 0; j--){ if (arr[j] > tmp) { arr[j+1] = arr[j]; } else {
break;
}; }; // 插入取出的数组元素 arr[j+1] = tmp; }; return arr; }
4、希尔排序:
(1)平均时间复杂度:O(nlogn) ~ O(n2)
(2)最好时间复杂度:O(n1.3)
(3)最坏时间复杂度:O(n2)
(4)空间复杂度:O(1)
(5)稳定性:不稳定
(6)JavaScript实现:
// 插入排序 function sort( arr, di ){ for(var i = di; i < arr.length; i++){ var guard = arr[i]; for(var j =i -di; j >= 0 && guard < arr[j]; j -= di){ arr[j+di] = arr[j]; }; arr[j+di] = guard; }; return arr; } // 希尔排序,本质上是以不同的步长多次进行插入排序 // 步长的选择对希尔排序的效率有显著影响 function shell ( arr ) { var di = parseInt( arr.length / 2 ); while ( di >= 1) { arr = sort( arr, di); di = parseInt( di / 2 ); }; return arr; };
5、归并排序:
(1)平均时间复杂度:O(nlogn)
(2)最好时间复杂度:O(nlogn)
(3)最坏时间复杂度:O(nlogn)
(4)空间复杂度:O(n)
(5)稳定性:稳定
(6)JavaScript实现:
// 对被归并的左右两个数组进行归并排序 // 被输入的左右两个数组,都是有序的。 function merge (left, right){ var l = 0, r = 0; var result = []; // 对左右两个数组的首项,进行比较,较小的推入栈中。 while(l < left.length && r < right.length){ if(left[l] < right[r]){ result.push( left[l] ); l += 1; } else { result.push( right[r] ); r += 1; }; }; // 经过上面的比较,左右两个数组,必定有一个数组比较完毕,一个没有比较完毕。 // 但是,在不同情况的递归层,有不同的表现,故而将二者未比较的元素都连接到result中。 // 由于,左右两个数组在输入前就是有序的,剩余未经比较的数组元素也是有序的,且都大于之前经过比较的数组元素,故而可以将其连接到result。 // 下方的代码,实质上是将左右数组中,未经比较的数组元素连接到result。 result = result.concat( left.slice(l) ); result = result.concat( right.slice(r) ); return result; }; function mergeSort ( arr ){ var len = arr.length; // 结束递归 if(len <= 1){ return arr; }; // 切割数组,并对切割后的数组进行递归操作 var middle = Math.floor( len/2 ); var left = mergeSort( arr.slice(0, middle) ); var right = mergeSort( arr.slice(middle) ); // 完成递归后,进行归并 return merge(left, right); }
6、快速排序:
(1)平均时间复杂度:O(nlogn)
(2)最好时间复杂度:O(nlogn)
(3)最坏时间复杂度:O(n2)
(4)空间复杂度:O(logn) ~ O(n)
(5)稳定性:不稳定
(6)JavaScript实现:
function quick ( arr ) { var less = [], pivotList = [], more = [], result = [], len = arr.length; // 结束递归 if(len <= 1){ return arr; }; // 与基准对比,将数组划分为小,中,大三组 var pivot = arr[0]; for(var i = 0; i <len; i++){ if(arr[i] < pivot){ less.push(arr[i]); } else if(arr[i] > pivot){ more.push(arr[i]); } else { pivotList.push(arr[i]); }; }; // 递归地对划分出的小、大两个组进行快速排序 less = quick(less); more = quick(more); // 将排序好的小,中,大三组连接起来 result = result.concat(less, pivotList, more); return result; }