標籤:情況 中間 遞迴 判斷 數組 快速 效能 組合 排序
概述
快排就是找一個基數用來比較
把比他大的放他前面,比他小的放他後面
然後把前後兩部分重複此方法排序
通俗易懂版本
let list = [2, 3, 1, 9, 5, 6, 4, 7, 8];let quick = function(arr) { if (arr.length < 1) { return arr; } let base = arr[0], left = [], right = []; for (let i = 1; i < arr.length; i++) { if (arr[i] < base) { left.push(arr[i]) } else { right.push(arr[i]) } } return arguments.callee(left).concat(base, quick(right))}let result = quick(list);console.log(result)
這個方法比較簡單,直接建立數組,把比基數小的放前面數組,大的放後面數組。然後利用數組合并就是排序後的數組。但是重複建立了很多數組對象,加上遞迴的原因,這裡對效能是一種嚴重的浪費。
抽象版本
let quickSort = function(arr, startIndex, endIndex) { if (startIndex > endIndex) { return; } let left = startIndex, right = endIndex, base = list[startIndex]; while (left !== right) { while (right > left && arr[right] >= base) { right--; } while (left < right && arr[left] <= base) { left++; } if (left < right) { let temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; } } arr[startIndex] = arr[right]; arr[right] = base; arguments.callee(arr, startIndex, left - 1); arguments.callee(arr, left + 1, endIndex)}quickSort(list, 0, list.length - 1);console.log(list)
- 這裡就不是利用建立數組歸類的方式了,而是直接修改原數組,避免了不必要的建立數組對象。缺點是看起來不是那麼明朗。
- 首先缺點一個用來比較的基數(不一定是第一個數)
- 從數組最後向前找比基數小的數,找到一個就停下,此時
right指向右邊第一個比基數小的數。
- 從數組左邊向後找比基數大的數,找到一個就停下,此時
left指向左邊第一個比基數大的數。
- 互換這兩個數,這就保證了基數兩邊,左邊是小的,右邊是大的。
- 當
right與left碰頭時,停止。因為此時left遍曆過的都是比基數小的,right遍曆過的都是比基數大的,沒必要在找下去。
- 能讓
right指標停下來的數肯定是比基數小的數,因為這裡基數是第一個,所以基數要與比它小的數換位置。
- 註:
left停下的時候指向的是大於基數的數,要這個數沒用,因為基數已經在第一個了,left指向的數肯定在它後面,已經是正確的情況。如果我們取得基數是中間的某個值,這時候就得判斷指標位置和數值大小再確定換不換位置。由於外層迴圈結束時right位置使我們需要的位置,所以應該先從右往左開始找小的。如果先由左往右,left指向一個比基數大的數停下了,這時候right也與left相遇了,但這時指向的數是比基數大的數,顯然不是我們需要的。先從右開始就不一樣了,right鎖定的是比基數小的,left撞上right時指向的數就是比基數小的數。
- 換一種說法:先從右找的原因是要找一個比基數小的跟基數換位,實現小的在基數前面。但是這樣不能保證基數前面都比他小。所以還需要從前面找找比基數大的,找到了就和已經找到的小的數互換,找不到就是
right與left相遇,迴圈結束,將基數與right指向的數換位。
- 最後把基數兩邊的數重複上面步驟。
javascript 快速排序