目錄
荷蘭國旗問題
描述
荷蘭國旗有三種條紋構成,自上到下條紋的顏色依次爲紅、白、藍。現有若干紅、白、藍三種顏色的條紋序列,要將它們重新排列使所有相同顏色的條紋在一起。本問題要求將所有紅色的條紋放最上邊、所有白色的條塊放中間、所有藍色的條紋放最下邊。(如下所示)
實際上可以把題目簡化爲編程題目:
給定一個數組arr,和一個數num,請把小於num的數放在數組的左邊,等於num的數放在數組的中間,大於num的數放在數組的右邊。要求額外空間複雜度O(1),時間複雜度O(N)。
題目思路:實際上類似於快排的思想,設3個移動變量,假設
int arr[10] = {2,5,1,3,4,9,5,8,5,7};
num = 5; //中間數
假設三個指針,分別指向數組的最左側減一,最右側加1,以及數組最左端。
開始排序:
1.當 i 指向 第0位 時,發現 arr[0] 小於 num(也就是5), 那麼便 (L-1)+1 = L 位與 第 i 位進行交換,並且各向前移動一位,變成如下:(由於L位和 i 位恰好都爲 0 ,所以發生自身與自身交換)
2.當 i 指向 第1位 時,發現 arr[1] 等於 num, 那麼 i 向前移動一位,由於左邊不交換,L的位置不動,變成如下:
3.當 i = 2 時,發現 arr[2] 小於 num, 那麼便 L+1 位與 第 i 位進行交換,並且各向前移動一位,變成如下:
4. i = 3, i = 4 都是小於 num,所以操作跟步驟3 一樣,得到如下。此時 i = 5 ,arr[5] = 9 > num,所以arr[i] 與 arr[(R+1)-1]進行交換,這裏注意,由於交換以後原來的arr[(R+1)-1]的值並不一定小於等於num,所以我們不能讓 i 前進一步,必須繼續判斷 arr[i] 與 arr[R - 1] 的值,進行交換,以此類推,直到不交換爲止,圖示如下:
5.這裏到最後一步,i = 7,arr[7] = 8 > num ,那麼便使得 arr[7] 與 arr[R - 1]交換,這裏可以看出 R - 1 = 7,所以需要停止搜索了,終止的條件就是 i 與右邊指針所指相等。
代碼很簡單如下:
void mySwap(int * a, int *b){
if(a != b){
(*a) ^= (*b);
(*b) ^= (*a);
(*a) ^= (*b);
}
}
void mySort(int *arr, int L,int R, int num){
int i = 0;
while(i < R){
if(arr[i] < num)
mySwap(&arr[++L],&arr[i]);
else if(arr[i] > num){
mySwap(&arr[--R], &arr[i]);
continue;
}
i++;
}
}
int main()
{
int arr[10] = {2,5,1,3,4,9,5,8,5,7};
mySort(arr,-1,10,5);
for(int i =0; i<10; i++){
cout<<arr[i]<<" ";
}
return 0;
}
快排改進(隨機快排)
通過上面的思想實際上我們可以對快排進行改進,快排的思想是拿取一個數字然後把其定位到正確的位置;但是實際上數組中不一定只有一個大小爲拿取數大小的數字,可能有一批數字均相等,此時我們便可以利用上述問題的解決方法進改進。
- 把數組分成三塊小於num,等於num,大於num;之後進行遞歸時只要對小於和大於兩邊的數組進行排序即可,這樣效率也會提升。
- 其次,由於在快排中,我們通常拿取的比較數字一般是首個或者末尾,但是這樣如果遇到 順序數列 {5,4,3,2,1}或者{1,2,3,4,5},效率會大大降低,使得時間複雜度可能降爲O(N^2);爲了提高效率,我們可以採取隨機拿取某個數來進行比較,這個方法數學推導也證明了期望時間複雜度爲 O(NlogN)。
代碼如下:
void mySwap(int * a, int *b){
if(a != b){
(*a) ^= (*b);
(*b) ^= (*a);
(*a) ^= (*b);
}
}
void quickSort2(int *arr, int left, int right){
if(left < right){
mySwap(&arr[left + rand()%(right-left+1)],&arr[right]); //隨機拿取
int i = left, L = left - 1, R = right;
while(i < R){
if(arr[i] < arr[right])
mySwap(&arr[++L],&arr[i++]);
else if(arr[i] > arr[right])
mySwap(&arr[--R],&arr[i]);
else
i++;
}
mySwap(&arr[R],&arr[right]);//arr[right]最後進行交換,前面不變
quickSort2(arr,left,L);
quickSort2(arr,R+1,right);
}
}