快速排序離不開遞歸的思想,你若是不瞭解遞歸,能夠結合我另一篇文章來學習 算法入門之遞歸分而治之思想的實現javascript
網上有有趣的動態圖來表示快速排序,但其實咱們大部分程序員都是腦子不太好使那種,即便看了形象生動的動態圖,仍是想不到具體實現思路。java
排序都有基本的步驟,快排也不例外,一般分爲這麼幾步:程序員
一、選擇基準值;算法
二、須要2個空數組,分別位於基準值的左邊和右邊,小於基準值的push到左邊的數組,大於基準值的push到右邊的數組;segmentfault
三、遞歸重複上面的步驟。數組
原始數組 | [2, 4, 1, 5, 3, 1] |
---|---|
找基準值 base | 末尾元素1 |
拆分 | left [1] <- [base] -> [2, 4, 5, 3] right |
遞歸 | 對left和right的數組重複第一步找新的基準值 |
模擬遞歸1 | [1], [1], [2] <- [3] -> [4, 5] |
模擬遞歸2 | [1], [1], [2], [3], [4] <- [5] -> [] |
遞歸結束,合併數組 | [...[1], ...[1], ...[2], ...[3], ...[4], ...[5]] |
這個表格模擬快速排序的具體步驟,遞歸是將一種規律重複執行N次的操做,咱們找到快速排序的規律,而後return 遞歸,當遞歸到數組爲1個元素時,再也不遞歸,由於只剩一個元素的數組不須要再比較了。函數
理論理解起來很容易,但常常是實際寫代碼,無從下手,下面是我根據快排的步驟實現的遞歸快速排序。qSort函數不復雜,他表示執行一次找基準值而且遍歷比較的過程,而你可能不太理解的是函數最後面的return。學習
return [...qSort(left), ...[base], ...qSort(right)]
將這個return拆分開來看。code
一、返回值應該是個數組 。排序
return []
二、合併第一次快速排序的left,base,right數組。接着就交給遞歸去執行左邊和右邊數組的排序。
return [qSort(left), [base], qSort(right)]
三、由於qSort返回的是數組,不是數組元素,因此須要用ES6語法...來散列開。
完整代碼:
function qSort(arr) { //聲明並初始化左邊的數組和右邊的數組 var left = [], right = [] //使用數組最後一個元素做爲基準值 var base = arr[arr.length - 1] //當數組長度只有1或者爲空時,直接返回數組,不須要排序 if(arr.length <= 1) return arr //進行遍歷 for(var i = 0, len = arr.length; i < len - 1; i++) { if(arr[i] <= base) { //若是小於基準值,push到左邊的數組 left.push(arr[i]) } else { //若是大於基準值,push到右邊的數組 right.push(arr[i]) } } //遞歸而且合併數組元素 return [...qSort(left), ...[base], ...qSort(right)] } const arr = [2, 4, 1, 5, 3, 1] const s = qSort(arr) console.log(s) // [1, 1, 2, 3, 4, 5]
快速排序的平均時間複雜度是O(nlogn),最差狀況是O(n²)。