JS快速排序&三路快排

草榴社群發表於2019-02-15

參考快速排序演算法的優化思路總結

參考演算法與面試之-如何準備演算法面試

快速排序

快速排序是什麼 快速排序是圖靈獎得主C. A. R. Hoare(1934--)於1960時提出來的。

JS快速排序&三路快排
快速排序是對氣泡排序的一種改進。它的基本思想是:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一不部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。 整個排序過程只需要三步:

  • 在資料集之中,選擇一個元素作為"基準"(pivot)。
  • 所有小於"基準"的元素,都移到"基準"的左邊;所有大於"基準"的元素,都移到"基準"的右邊。
  • 對"基準"左邊和右邊的兩個子集,不斷重複第一步和第二步,直到所有子集只剩下一個元素為止。

引自wikipedia 快速排序(英語:Quicksort),又稱劃分交換排序(partition-exchange sort),一種排序演算法,最早由東尼·霍爾提出。在平均狀況下,排序n個專案要Ο(n log n)次比較。在最壞狀況下則需要Ο(n2)次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他Ο(n log n)演算法更快,因為它的內部迴圈(inner loop)可以在大部分的架構上很有效率地被實現出來。

步驟

  1. 找到該陣列的基準點(中間數),並建立兩個空陣列left和right;
  2. 遍歷陣列,拿出陣列中的每個數和基準點進行比較,如果比基準點小就放到left陣列中,如果比基準點大就放到right陣列中;
  3. 對陣列left和right進行遞迴呼叫。

方法一

    function quickSort(arr) {
    	if (arr.length<=1) {return arr;}
    	var left = [],
    		right = [],
    		baseDot =Math.round(arr.length/2),
    		base =arr.splice(baseDot, 1)[0];
    
    	for (var i =0; i <arr.length; i++) {
    		if (arr[i] < base) {
    			left.push(arr[i])
    		}else {
    			right.push(arr[i])
    		}
    	}
    
    	return quickSort(left).concat([base], quickSort(right));
    }
複製程式碼

實現一個quickSort的封裝,並且定義left和right,找到陣列的基準點baseDot和對應的基數base,然後遍歷陣列的每一項和base進行對比,最後遞迴呼叫,給出一個跳出條件if (arr.length <= 1) {return arr;}

方法二

    function quickSort(array, left, right) {
    	var length =array.length;
    		left =typeof left ==='number'? left :0,
    		right =typeof right ==='number'? right : length-1;
    
        if (left < right) {
            var index = left -1;
            for (var i = left; i <= right; i++) {
                if (array[i] <= array[right]) {
                    index++;
                    var temp = array[index];
                    array[index] = array[i];
                    array[i] = temp;
                }
            }
            quickSort(array, left, index -1);
            quickSort(array, index +1, right);
        }
        return array;
    }
複製程式碼

快速排序的基本思想就是分治法

引自wikipedia 在電腦科學中,分治法是建基於多項分支遞迴的一種很重要的演算法正規化。字面上的解釋是“分而治之”,就是把一個複雜的問題分成兩個或更多的相同或相似的子問題,直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合併。

快速排序的改進方法:三路快排

定義

三路快速排序是快速排序的的一個優化版本, 將陣列分成三段, 即小於基準元素、 等於 基準元素和大於基準元素, 這樣可以比較高效的處理陣列中存在相同元素的情況,其它特徵與快速排序基本相同。

我這裡簡單概括一下思路,有興趣的同學可到上面的連結上閱讀:快速排序及優化(Java實現)

  • 隨機選取基準值base(支點隨機選取),參考快速排序演算法的優化思路總結
  • 配合著使用插入排序(當問題規模較小時,近乎有序時,插入排序表現的很好)
  • 當大量資料,且重複數多時,用三路快排
<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			console.time("test0")
			function qSort(arr) {
				if(arr.length == 0) {
					return [];
				}
				var left = [];
				var right = [];
				var pivot = arr[0];
				for(var i = 1; i < arr.length; i++) { // 注意這裡的起始值,因為有一個作為flag了
					if(arr[i] < pivot) {
						left.push(arr[i]);
					} else {
						right.push(arr[i]);
					}
				}
				return [...qSort(left), pivot, ...qSort(right)];
			}
			console.log(qSort([9, 4, 10, 3, 1, 1, 0, 10, 8, 3, 9, 9, 4, 10, 10, 9, 9, 9, 1, 0]));
			console.timeEnd("test0")
		</script>
		<script type="text/javascript">
			console.time("test1")
			function qSort3(arr) {       //三路快排
				if(arr.length == 0) {
					return [];
				}
				var left = [];
				var center = [];
				var right = [];
				var pivot = arr[0];    //偷懶,直接取第一個,實際取值情況 參考[快速排序演算法的優化思路總結]
				for(var i = 0; i < arr.length; i++) {      
					if(arr[i] < pivot) {
						left.push(arr[i]);
					} else if(arr[i] == pivot) {
						center.push(arr[i]);
					} else {
						right.push(arr[i]);
					}
				}
				return [...qSort3(left), ...center, ...qSort3(right)];
			}
			console.log(qSort3([9, 4, 10, 3, 1, 1, 0, 10, 8, 3, 9, 9, 4, 10, 10, 9, 9, 9, 1, 0]))
			console.timeEnd("test1")
		</script>
	</head>

	<body>
	</body>

</html>
複製程式碼

JS快速排序&三路快排

JS快速排序&三路快排

JS快速排序&三路快排

可以看到對有重複資料的資料優化還是很可觀的。。

相關文章