July收集荷兰国旗问题之三路partition

本文探讨了荷兰国旗问题的解决方法,包括利用lumoto版本的partition进行高效排序,详细解释了算法过程和优化策略,同时分析了不同排序场景下的循环不变量,并提供了修正后的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题目和分成两块的partition的扩展,例如有一堆0 1 2 数字组成的数组,要分成 00 00  11 1 1  222 2这种顺序的。


利用lumoto版的partition可以很好的解决,比hoare好多了,而且直接利用loop invariant,变成i j k三个指针,[low,i]=0 [i+1,j]=1, [j+1,k-1]=2, 里面如果新来2的话,直接k++,

如果是1的话,需要和a[j+1] swap, 同时j++, 如果0的话,需要先和a[i+1] swap i++, 然后和 a[j+1] swap j++, 因此算法如下:

void NertherlandFlags(int *a, int n)
{
	int low=0,high=n-1;
	int i=low-1,j=low-1;
	for(int k=low;k<=high;k++)
	{
		if(a[k]==2) ;
		else if(a[k]==1) 
		{
			j++;
			swap(a[j],a[k]);
		}
		else if(a[k]==0)
		{
			i++;
			swap(a[i],a[k]);
			j++;
			swap(a[j],a[k]);
		}
	}
}
代码比较好写,感觉这都是一类题,

1.快排的partition,注意留一个pivot,算导是留最后一个,所以loop到high-1就停了,里面和pivot比,最后加一次swap把pivot放中间

loop invariant:  [low,i] <pivot, [i+1, j-1]>pivot, =放那边都行,exit loop时 j=high, 最后把swap跳进来

2.奇偶排序,整个区间划分为左奇右偶,和%2=0 =1比,loop 到high,
loop invariant:  [low,i] 奇, [i+1, j-1]偶, exit时 j=high+1, 包含整个区间了

3.荷兰国企问题,整个区间划分为0 1 2 (红 黄 蓝三块), loop 到high,

loop invariant:  [low,i] 0, [i+1, j] 1, [j+1, k-1]  exit时 j=high+1, 包含整个区间了


抱歉大家,这道荷兰国旗代码有bug,我才知道的,后经过分析主要是前面只有2 或者0 2时,如果来了0,后面swap(a[j],a[k]) 会多交换一次使得交换回去,所以如果只有0的情况,其实不需要交换,而swap(a[j],a[k]) swap(a[j],a[k])都是子交换,因此1次两次不影响,于是统一到一起就是没有1区间的时候,也即[i+1,j]区间空,根据性质最多相差1,因此是i==j的时候出错,所以此时少一次swap, 但是i++ j++需要的 保持ij同步 

事实证明未经过OJ测试的代码很难保证正确性。leetcode setcolor题 就是上面的挂了,于是经过多种组合条件分析发现bug,单独处理1 interval空的情况

void sortColors(int a[], int n) {
        int i=-1,j=-1;
        for(int k=0;k<=n-1;k++)
        {
            if(a[k]==0)
            {
                if(i==j)//before are 2 or 0 2, swap one is only, two will error, also 0 swap once is ok, so that is no 1 interval would only swap once  
                {
                    i++;
                    swap(a[i],a[k]);
                    j++;
                }
                else
                {
                    i++;
                    swap(a[i],a[k]);
                    j++;
                    swap(a[j],a[k]);
                }
            }
            else if(a[k]==1)
            {
                j++;
                swap(a[j],a[k]);
            }
        }
    }


附上July版本,前面 0 1区间 最后面2区间  1 2 之间没处理的


void sortColors(int a[], int n) {
        int begin=0,end=n-1,current=0;
        while(current<=end)
        {
            if(a[current]==0)
		        swap(a[begin],a[current]),begin++, current++;
	        else if(a[current]==1)
		        current++;
	        else if(a[current]==2)
		        swap(a[current],a[end]),end--; //current not move
        }
    }
这种不用考虑特殊情况,比如 只有2 和只有0 2的区间的情况,其实也是单向扫描过来的,只是调整了未处理部分和 0 1 2 区间的顺序而已,因为指针从current+1, 到end处理了,一个

指针扫描的,还是单向扫描好,其实也不是Hoart版啦,所以自己不用管Hoard版,坚持Lumoto版就可以了,sumous_t大神似乎也是的。


似乎还有一种改进第一个版本的思路,就是不swap,而是覆盖,像优化partition一样的

附上July博客 https://github.com/bolpigo/The-Art-Of-Programming-By-July/blob/master/ebook/zh/02.07.md

sumous_t 大神代码: https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/code/python/2.8:%20%E8%8D%B7%E5%85%B0%E5%9B%BD%E6%97%97%E9%97%AE%E9%A2%98.py


再附上sumous_t大神帮我修改后AC的代码,膜拜下大神,还是女博士哦:)

void sortColors(int a[], int n) {
        int low=0,high=n-1;  
    int i=low-1,j=low-1;  
    for(int k=low;k<=high;k++)  
    {  
        if(a[k]==2) ;  
        else if(a[k]==1)   
        {  
            j++;  
            swap(a[j],a[k]);  
        }  
        else if(a[k]==0)  
        {  
			
	    i++;j++;swap(a[j],a[k]);swap(a[j],a[i]);

        }  
    }


荷兰国旗问题是经典的排序算法题目,它利用了分治策略和数组原地操作的思想。这个任务的目标是将一个包含三种颜色(红、白、蓝)的整数数组,按照“红色 -> 白色 -> 蓝色”的顺序排列。以下是C语言的一个简单实现: ```c #include <stdio.h> void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } void partition(int arr[], int low, int high) { int pivot = arr[high], i = (low - 1); // 将最后一个元素作为基准 for (int j = low; j <= high - 1; j++) { if (arr[j] == 0) { // 红色元素 i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); } void quicksort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quicksort(arr, low, pi - 1); // 对左边部分递归排序 quicksort(arr, pi + 1, high); // 对右边部分递归排序 } } void dutch_flag_problem(int arr[], int n) { quicksort(arr, 0, n - 1); } int main() { int arr[] = {1, 0, 2, 0, 2, 1}; int n = sizeof(arr) / sizeof(arr[0]); printf("Original array: "); for (int i = 0; i < n; i++) printf("%d ", arr[i]); dutch_flag_problem(arr, n); printf("\nSorted array after Dutch flag problem: "); for (int i = 0; i < n; i++) printf("%d ", arr[i]); return 0; } ``` 在这个程序中,`quicksort`函数负责排序,`partition`函数则用于将数组划分为两部分,红色元素都在左侧,蓝色元素都在右侧,而白色元素居中。最后,`dutch_flag_problem`调用快速排序完成整个过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值