思路:將要排序的數組從中間分紅兩部分,分別排序,再將排序好的兩部分合並。算法
這裏用到了分治思想:分而治之,講一個大問題分解成若干個小問題來解決。很明顯這裏須要用到遞歸這種編程方式。編程
function mergeSort(array, region1, region2) {
var tempArray = [];
var i = region1[0];
var j = region2[0];
for (; i <= region1[1]; i++) {
for (; j <= region2[1]; j++) {
if (array[i] > array[j]) {
tempArray.push(array[j]);
} else {
break;
}
}
tempArray.push(array[i]);
}
for (; j <= region2[1]; j++) {
tempArray.push(array[j]);
}
var n = 0;
for (let k = region1[0]; k <= region2[1]; k++) {
array[k] = tempArray[n++];
}
return [region1[0], region2[1]];
}
function divide(array, start, end) {
if (start >= end) return [start, end];
var mid = Math.floor((end+start)/2);
return mergeSort(array, divide(array, start, mid),divide(array, mid+1, end));
}
複製代碼
分析:數組
穩定的排序;bash
根據遞推代碼求時間複雜度的方法,分析👆代碼時間複雜度:歸併排序的執行效率與數據有序度無關,全部時間複雜度O(nlogn);ide
每次合併時,會臨時申請一個最大不超過n的內存空間,合併完成釋放。而空間複雜度是指算法運行時須要的額外空間,每次執行時函數都僅僅申請了一塊內存空間,但並無累積。所以空間複雜度O(n),不是原地排序,這也是歸併排序不如快速排序應用普遍的緣由;函數
思路: 一樣採用分治思想。 從數組中選一個位置的數據,小於它的放左邊,大於它的放右邊。以後再分別對左右兩邊再次進行一樣操做以此類推。直到間距縮小到1,說明數據都有序了。其實就是每次經過分區的方式找到一個元素在有序後的數組中的位置。ui
總結就是:spa
// 若是pivot==end則只需從一頭開始查找了
function quickSort(array, start, end) {
if (start >= end) return;
var pivot = divide(array, start, end);
quickSort(array, start, pivot-1);
quickSort(array, pivot+1,end);
}
function divide(array, start, end) {
var pivot = end;
// i表明小於pivot的區域邊界
var j = 0;
var i = 0;
while (i <= pivot) {
if (array[j] <= array[pivot]) { // 由於此時插入操做不要求保證順序,用交換就行
if (array[i] != array[j]) {
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
i++;
}
j++;
if (j >= pivot) break;
}
// 把pivot插入到小於區域的末尾
temp = array[i];
array[i] = array[pivot];
array[pivot] = temp;
pivot = i;
return pivot;
}
複製代碼
對數組進行分區操做中,爲了進行原地排序,空間複雜度爲O(1),又儘量不進行移動,採用了相似插入排序的方式,同時對數組的插入操做採用交換的方式。3d
而這種交換操做就會形成排序算法的不穩定。code
時間複雜度:平均時間複雜度O(nlogn);最壞是O(n2);
能夠發現歸併是先處理子問題,而後再合併。而快速則是先對大區域分區,在對子區域分區處理。
除了對無序數組進行排序外,還能夠解決如:求無序數組中第K大元素,這樣的問題。 快速排序每次分區都會找到pivot元素排序的位置,所以能夠每次分區後比較K和pivot的位置大小,進行更加細化的查找。時間複雜度= n+n/2+n/4+n/8+...+1 = O(n);