快排2 經典快排和荷蘭國旗快排

2021-09-06 22:07:19 字數 2634 閱讀 3206

基礎知識見:

《建議先閱讀基礎知識,並自己手推一遍》

演算法原理:

第一步:取陣列最後乙個數作為num,將陣列中的 <= num的數放在陣列的左邊,> num的數放在陣列的右邊,這是可以理解為分成了兩個陣列;

第二步:然後將 <= num的部分當成乙個陣列,繼續第一步;> num的部分同理;

第三步:若陣列的大小  < 2,則結束。

流程圖:

以下列陣列為例子:

圖中,可以看到每次將陣列partition過程中,都是將左陣列中最後乙個數排除掉(因為我們的基數是選擇陣列最後乙個數,而且partition是將陣列分為<=和》部分)。若不將partition後左陣列最後乙個數(這個數必定是基數)排除掉,那麼遞迴將無限進行。

**實現

int partition(std::vector&arr, int left, int right, int num)

} return pos;

}void classicquicksort(std::vector&arr, int left, int right)

int num = arr[right];

int pos = partition(arr, left, right, num);

classicquicksort(arr, left, pos - 1);

classicquicksort(arr, pos + 1, right);

}

經典快排中的技術選擇是陣列最後乙個數,而隨機快排基數的選擇是隨機的,其實也就是partition中num的選擇,所以將陣列的最後乙個數與隨機數交換位置。

**如下:

void randomquicksort(std::vector&arr, int left, int right)

srand(unsigned(time(0)));

int arraysize = right - left + 1;

int randomindex = rand() % arraysize + left;

int num = arr[randomindex];

int temp = arr[right];

arr[right] = num;

arr[randomindex] = temp;

int pos = partition(arr, left, right, num);

randomquicksort(arr, left, pos - 1);

randomquicksort(arr, pos + 1, right);

}

演算法原理第一步:取陣列最後乙個數作為num,將陣列中的 < num的數放在陣列的左邊,=num的數放在陣列中間,> num的數放在陣列的右邊,這是可以理解為分成了3個陣列;

第二步:然後將 num的部分同理;

第三步:若陣列的大小  < 2,則結束。

流程圖:

以下列陣列為例子:

**實現

std::vectorpartition1(std::vector&arr, int left, int right, int num)

else if (arr[i] == num)

else

}result[0] = posleft;

result[1] = posright;

return result;

}void dutchflagquicksort(std::vector&arr, int left, int right)

int num = arr[right];

std::vectorpos = partition1(arr, left, right, num);

dutchflagquicksort(arr, left, pos[0]);

dutchflagquicksort(arr, pos[1], right);

}

快排最好的時間複雜度為o(n*logn),最壞的時間複雜度為o(n^2);空間複雜度為o(logn),最差空間複雜度為o(n)。同時快排是個不穩定的排序,那麼穩定性的概念是什麼?

表示兩個值相同的元素在排序前後是否有位置變化

所以從上述流程圖可以明顯看出,相同兩個值的相對前後位置是會發生變化的,所以快排不穩定。

那為什麼快排的空間複雜度為o(logn)?

空間浪費在記錄邊界處。

快排其實很好理解,自己畫個圖,完整走個流程就ok了。**實現其實只要主要一些小細節,比如說經典快排中要主要避免無限遞迴,partition中的迴圈引數判斷等。

但是工程上不能用遞迴函式。所以工程上實現快排,不用遞迴。

利用荷蘭國旗問題改進經典快排和隨機快排

每次取陣列中最後乙個值,依照這個值把陣列分為兩份,小於的在左邊,大於的在右邊。再依次按照這樣的思想進行操作。ps 荷蘭國旗問題可以看另一篇部落格 荷蘭國旗問題把陣列是分為三個部分的,小於 等於 大於這三個部分。按照這樣的思想,等於部分就不需要進行再次進行排序,這樣就能減少很大一部分的開銷。改進之後的...

演算法 快速排序 經典快排 隨機快排

經典快排的思路是選取陣列的最後乙個數 x,按照問題一的思路把整個陣列劃分成小於等於 x 大於 x兩個部分,將 x 和 大於 x 部分陣列的第乙個元素交換位置。此時整個陣列劃分成小於等於 x x 大於 x三個部分,也就是這一次排序將 x 值排好位置。再分別對小於等於 x和大於 x中的陣列遞迴劃分,直到...

快排和堆排

一 快速排序 最常用的排序演算法,速度通常也是最快的。時間複雜度 o nlogn 最壞 o n 2 空間複雜度 o nlgn 不穩定 比如 5 3 3 4 3 8 9 10 11 這個序列,在中樞元素5和3交換就會把元素3的穩定性打亂 實現原理 快排主要是通過選擇乙個關鍵值作為基準值。比基準值小的都...