JS實現快速排序(QuickSort)
偶然看到阮一峰老師部落格中幾年前的一個快速排序演算法,每次迴圈一次都要建立兩個額外陣列,如果資料量大的話要佔用不少額外記憶體。但是陣列是引用型別,是可修改的,可以直接操作原陣列本身來節約記憶體。
下面自己寫了一個,當做練手。(除去標準的雙向分類外,還稍稍優化了程式碼,也加了單項優化方法,使其更加簡潔)
快速排序方法的關鍵在於選取一個值,將整個陣列分為兩部分,小的在左,大的在右,下面就是這個函式的寫法:
//該函式的主要目的是交換陣列中兩個元素的位置 function swap(arr, index1, index2) { let data = arr[index1]; arr[index1] = arr[index2]; arr[index2] = arr[index1]; //陣列是引用型別,允許修改原陣列。 } //選取隨機值,將陣列分為兩部分 function partition(arr, start, end) { let keyIndex = end, key = arr[keyIndex]; //將隨機值(以後稱key值)定為最後一個數,也可以真的隨機選取,見下一行 // let keyIndex = Math.floor(Math.random() * (end - start)) + start; let i = start, j = end, order = true; //當order為true時正向篩選,當order為false時逆向篩選 //先從正向開始,因為我們把key值儲存到了陣列的結尾處。 while(i != j) { if(order) { //正向篩選 if (arr[i]>key) { swap(arr, i, j); //將大於key的數字和key進行交換 order = false; } else { i++; } } else { //逆向篩選 if(arr[j]<key) { swap(arr, i, j); //將小於key的數字和key進行交換 order = true; } else { j--; } } } return i;//返回key值最終的位置 }
觀察分組演算法partition不難發現,其實i和j位置上始終有一個存著key值,然後和比它大或者比它小的值進行交換。那麼我們也可以將其寫成一個單向的分組方法:
function partition2(arr, start, end) { let keyIndex = end, key = arr[end]; let i = start -1, j = start; for (;j<end;j++) { if (arr[j]< key) { // i位置的值永遠比key值小 i++; if (i != j) { swap(arr, i, j); } } } ++i; swap(arr, i, end); return i; //返回key值最終的位置 }
接下來遞迴呼叫分組函式,將整個陣列排序:
function quickSort(arr, start, end) {
if (start == end) return;
let index = partition(arr, start, end);
if (index > start){
quickSort(arr, start, index-1);
}
if (index<end) {
quickSort(arr, index+1, end);
}
}