荷蘭國旗問題(快排改進——隨機快排)

目錄

荷蘭國旗問題

快排改進(隨機快排)


 

荷蘭國旗問題

描述  

       荷蘭國旗有三種條紋構成,自上到下條紋的顏色依次爲紅、白、藍。現有若干紅、白、藍三種顏色的條紋序列,要將它們重新排列使所有相同顏色的條紋在一起。本問題要求將所有紅色的條紋放最上邊、所有白色的條塊放中間、所有藍色的條紋放最下邊。(如下所示)

實際上可以把題目簡化爲編程題目:

給定一個數組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;
}

 

快排改進(隨機快排)

通過上面的思想實際上我們可以對快排進行改進,快排的思想是拿取一個數字然後把其定位到正確的位置;但是實際上數組中不一定只有一個大小爲拿取數大小的數字,可能有一批數字均相等,此時我們便可以利用上述問題的解決方法進改進。

  1. 把數組分成三塊小於num,等於num,大於num;之後進行遞歸時只要對小於和大於兩邊的數組進行排序即可,這樣效率也會提升。
  2. 其次,由於在快排中,我們通常拿取的比較數字一般是首個或者末尾,但是這樣如果遇到 順序數列 {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);
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章