簡單理解
首先我覺得我們要明確一般算法都是需要遞歸的,所以我們首先完成第一循環
第一個循環我們找到一個主元(數組的中間),我們把大於的放右邊,小於的放左邊
然後在分別把主元左邊的和右邊的在重複上面的過程就可以達到排序了
具體步驟
1.首先,從數組中選擇中間一項作爲主元
2.創建兩髮指針,一個指第一項(左邊),一個指最後一項(右邊)
3.我們要在左邊找大的值,右邊找小的值,讓他們相互交換,交換完後左邊++,右邊--,當達到左邊的指針和右邊的指針相同位置或者左邊的指針大於右邊指針的位置的時候聲明第一次循環結束了,在主元左邊都是比主元小的值,右邊都是大的值
4.在將主元左右兩邊分爲2個數組在進行上面的操作,(遞歸)
5.設置好遞歸出口,就是某一個主元他的左邊或者右邊只有一個值或者沒有值了的時候退出
代碼解析
準備
/*
* 普通的交換,將a[i]和a[j]的數值交換;
*/
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
首頁我們要遞歸完成,那麼我們就要寫出第一次循環的函數,然後在遞歸找出口
函數定義
/**
* 快排執行函數
* @param {Array} [array] 需要快拍的數組
* @param {string} [left] 左邊指針開始的位置
* @param {string} [right] 右邊指針開始的位置
*/
var partition = function (array, left, right) {
var pivot = array[Math.floor(left + right) / 2] // 主元
i = left; // 左邊指針開始指向位置
j = right; // 右變指針指向位置
}
函數第一次執行的代碼
/**
* 快排執行函數
* @param {Array} [array] 需要快拍的數組
* @param {string} [left] 左邊指針開始的位置
* @param {string} [right] 右邊指針開始的位置
*/
var partition = function (array, left, right) {
// 中間數
var pivot = array[Math.floor(left + right) / 2]
i = left; // 左邊指針開始指向位置
j = right; // 右變指針指向位置
while (i <= j) {
// 找大的
while (array[i] < pivot) {
i++
}
// 要找一個小的
while (array[j] > pivot) {
j--
}
// 對換
if (i <= j) {
swap(array, i, j)
i++
j--
}
}
return i // 爲什麼返回一個指針的位置,後面回說
}
把左指針開始向主元的方向++找到大於等於主元的值(找到後不動),開始右指針向主元方向--找到小於主元的值,當他們都找到的情況下,如果這個時候左指針和右指針沒有在同一個位置或者他們已經交替的情況(就是左指針的位置大於右指針),那麼就將左邊找到大於的值,和右邊找到小的值替換,然後左指針++,右指針--,直到左指針和右指針沒有在同一個位置或者他們已經交替的情況(就是左指針的位置大於右指針)的時候,那麼就可以是主元左邊全是大於的值,右邊全是小的值
左指針和右指針沒有在同一個位置或者他們已經交替的情況(就是左指針的位置大於右指針):這個是什麼意思?當左邊和右邊都開始找,當左邊大於或等於指針右邊指針了說明已經左邊都是小的了,右邊都是大的了,這個時候就可以停止了,
什麼時候的等於,就是一開始主元左邊都是小的,右邊都是大的值,當左邊指針和右邊指針同時到主元這個值的時候,左指針指向的值不小於主元(所以到主元這個時候暫停了),右指針不大於主元(到主元這個值也剛好停了)
什麼時候的左大於右:其他任意情況,當某一次換完了位置之後,我們在繼續指針在同時去找下一個值來對換的時候回進行左++,右--,然後發現,回判斷左邊是否大於右邊了,如果是那麼就第一次循環結束
開始遞歸
var quick = function (array, left, right) {
var index; // 接收回調函數返回的最終左邊指針返回的位置
if (array.length > 1) {
index = partition(array, left, right);
if (left < index - 1) {
quick(array, left, index - 1);
}
if (index < right) {
quick(array, index, right)
}
}
}
一旦開始遞歸處理的時候我們就要注意了,我們要先找遞歸的出口,然後在開始遞歸
思考:既然我要遞歸,那麼我們是要遞歸那個部分的,對了就是主元左邊的和右邊的,(雖然左邊的都是大的值,但是是沒順序的)
好既然我們要左邊的數組,和右邊的數組,那麼我們就需要某一個指針最後的位置來判斷右邊數組,和左邊數組
我們這裏用左邊指針的位置,所以上面我們返回的是i的值
出口:就是數組的長度要麼是0要麼是1,那麼我們就不需要了
那麼什麼情況下是0或者1呢?
左邊:left < (左邊指針的位置 -1),爲什麼這裏要減一,當第一次結束的時候左邊指針指向的值一點大於右邊指針指向的值,所以減一,那麼前面的值都是小值
右邊:(左邊指針的值)> right
因爲只有是大於或者小於了就說明至少數組是有2個值,那麼就可以繼續遞歸,
最終
從裏到外遞歸完後,那麼一個一個位置就回被按從小到大調整過來