快速排序是一種劃分交換排序。它採用了一種分治的策略,一般稱其爲分治法。算法
分治法的基本思想是:將原問題分解爲若干個規模更小但結構與原問題類似的子問題。遞歸地解這些子問題,而後將這些子問題的解組合爲原問題的解。數組
快速排序基於冒泡、遞歸分治。他在大數據狀況下是最快的排序算法之一,平均事件複雜度很低並且前面的係數很小,在大量隨機輸入的狀況下最壞狀況出現的機率是極小的。緩存
最壞時間複雜度:O($n^2$) 當選擇的基準值爲最大值或最小值時
穩定性:不穩定
平均時間複雜度:O(n*$log_2$n)
function quickSort(arr) { if(arr.length <= 1) { return arr; } let pivotIndex = Math.floor(arr.length / 2); let pivot = arr.splice(pivotIndex, 1)[0]; // let pivot = arr.splice(pivotIndex, 1); 3 < [9] //true let left = []; let right = []; for(let i = 0; i < arr.length; i++) { if(arr[i] < pivot) { left.push(arr[i]); } else { right.push(arr[i]); } } return quickSort(left).concat(pivot, quickSort(right)); }
上面簡單版本的缺點是,它須要Ω(n)的額外存儲空間,也就跟歸併排序同樣很差。額外須要的存儲器空間配置,在實際上的實現,也會極度影響速度和高速緩存的性能。
按照維基百科中的原地(in-place)分區版本,實現快速排序方法以下:性能
function quickSort(arr) { function swap(arr, i, k) { let temp = arr[i]; arr[i] = arr[k]; arr[k] = temp; } // 數組分區,左小右大 function partition(arr, left, right) { let storeIndex = left; let pivot = arr[right]; // 直接選最右邊的元素爲基準元素 for(let i = left; i < right; i++) { if(arr[i] < pivot) { swap(arr, storeIndex, i); storeIndex++; // 交換位置後,storeIndex 自增 1,表明下一個可能要交換的位置 } } swap(arr, storeIndex, right); // 將基準元素放置到最後的正確位置上 return storeIndex; } function sort(arr, left, right) { if(left > right) { return; } let storeIndex = partition(arr, left, right); sort(arr, left, storeIndex - 1); sort(arr, storeIndex + 1, right); } sort(arr, 0, arr.length - 1); return arr; }
利用分治法來處理快排,主要的思想是:大數據
步驟:ui
首先,把基準元素移到結尾(若是直接選擇最後一個元素爲基準元素,那就不用移動);
而後從左到右(除了最後的基準元素),循環移動小於等於基準元素的元素到數組的開頭,每次移動 storeIndex 自增 1,表示下一個小於基準元素將要移動到的位置;
循環結束後 storeIndex 所表明的的位置就是基準元素的全部擺放的位置;因此最後將基準元素所在位置(這裏是 right)與 storeIndex 所表明的的位置的元素交換位置。
完成一次分區;.net
tips:這裏爲何要把基準元素放到數組的最後一個元素的位置上,是爲了方便對數組中除了基準元素之外的全部元素進行遍歷,並方便在找到基準元素的排序位置 storeIndex
後進行兩兩交換。假若不如此,須要將該基準元素從原數組中取出來(相似阮一峯版作法arr.splice(pivotIndex, 1)
),循環遍歷完全部除基準元素外的元素後,找到基準元素的最後排序位置 storeIndex
後,須要將基準元素插入進來(用到插入排序的思想),顯然這種方式較爲複雜。code
因此通常選取了除數組最後一個元素爲基準元素後,會將該基準元素換到最後一個元素上;這裏便直接選取數組中最後一個元素爲基準元素,對整個數組進行分區操做[0~arr.length-1]
.固然也能夠只對數組中某一連續數組元素進行分區,即只對數組中這一小部分元素進行排序sort(arr, start, end);
。blog
function quickSort(arr, start, end) { function swap(arr, i, k) { let temp = arr[i]; arr[i] = arr[k]; arr[k] = temp; } // 數組分區,左小右大 function partition(arr, left, right) { let storeIndex = left; let pivot = arr[right]; // 直接選最右邊的元素爲基準元素 for(let i = left; i < right; i++) { if(arr[i] < pivot) { swap(arr, storeIndex, i); storeIndex++; // 交換位置後,storeIndex 自增 1,表明下一個可能要交換的位置 } } swap(arr, storeIndex, right); // 將基準元素放置到最後的正確位置上 return storeIndex; } function sort(arr, left, right) { if(left > right) { return; } let storeIndex = partition(arr, left, right); sort(arr, left, storeIndex - 1); sort(arr, storeIndex + 1, right); } sort(arr, start, end); return arr; } quickSort([3,7,8,5,2,1,9,5,4], 3, 7) // 只對部分元素排序
JS實現快速排序算法的詳細解釋
常見排序算法 - 快速排序 (Quick Sort)
算法的時間複雜度和空間複雜度-總結排序