荷兰国旗问题(快排改进——随机快排)

目录

荷兰国旗问题

快排改进(随机快排)


 

荷兰国旗问题

描述  

       荷兰国旗有三种条纹构成,自上到下条纹的颜色依次为红、白、蓝。现有若干红、白、蓝三种颜色的条纹序列,要将它们重新排列使所有相同颜色的条纹在一起。本问题要求将所有红色的条纹放最上边、所有白色的条块放中间、所有蓝色的条纹放最下边。(如下所示)

实际上可以把题目简化为编程题目:

给定一个数组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);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值