重新排列红蓝绿3色球 荷兰国旗问题

来源:互联网 发布:电脑总是弹出淘宝广告 编辑:程序博客网 时间:2024/05/02 00:26

Reorder Array of Red, Blue and Green balls(Dutch national flag problem)

一个有意思的问题:An array of some size contains Red, Blue and Green balls all mixed up randomly. like RGBBBRRGGG, where RGB is for Red, Green and Blue.

简单的说:有n个红蓝绿3种不同颜色的球,随机排成一列。现在需要使同种颜色的球排在一起并且按红蓝绿的顺序。(3中颜色简单的计为1 2 3)


这是经典的荷兰国旗问题(Dutch national flag problem,http://en.wikipedia.org/wiki/Dutch_national_flag_problem)。


1.当这个问题出现时,简单的方法是先扫描一遍序列,统计出各个颜色的个数,然后在数组中按各个颜色的个数填充各个颜色即可。

这个方法不错,但是需要2*n的时间。


2.这个问题类似于快速排序的数的交换。将比蓝色小的球放在左边,比蓝色大的球放在右边。 其中关键的是,出现了与蓝色相等的求的处理,例如:1 2 1 2 2 3 2 3的情况.

有一种处理方法,使用头尾两个指针,同时使用一个变量,记录第一次出现2颜色的位置(只需n步操作):

1.记录第一次出现2的位置。

2.头指针,从左向右扫描,a.出现比2小的的颜色,与第一次出现2的位置进行交换。如果没有出现过2,说明当前左边的颜色都比2小,无需处理。b.当出现比2大的颜色,记录位置,跳出。

3.尾指针,从右向左扫描,a.出现比2小的颜色,与第一次出现2的位置进行交换后,将交换后的颜色与上一步出现的比2大的颜色交换,跳出。b.出现和2相等的颜色,直接与上一步出现的比2大的颜色交换,跳出。

4.重复1 2 3步,直到头尾指针相遇。

#include <iostream>#include<stdlib.h>#include<stdio.h>#include<string.h>using namespace std;void swap(int *a, int *b){int tmp=*a;*a=*b;*b=tmp;}void partition_three_color(int *a,int low,int high){int i,j,tmp=-1;for(i=low;i<=high;i++){if(a[i]>2)//big color ,break, start from end to find a little colorbreak;else if(a[i]==2&&tmp==-1){//store the first 2tmp=i;}else{//now is small than 2, swap the first 2if(-1!=tmp){swap(a[i],a[tmp]);tmp++;}}}for(j=high;j>i;j--){if(a[j]<2){//find a little to swap big colorswap(a[tmp],a[j]);swap(a[j],a[i]);break;}else if(2==a[j]){//direct swapswap(a[i],a[j]);break;}}if(i+1<j-1)partition_three_color(a,i+1,j-1);}int main(){int n,i;while(scanf("%d",&n)!=EOF){//input total numbersint *arr=new int[n];for(i=0;i<n;i++){scanf("%d",&arr[i]);//only 1,2,3 three colorsif(arr[i]>3||arr[i]<1){printf("Invalid\n");return 0;}}partition_three_color(arr,0,n-1);for(i=0;i<n;i++)printf("%d ",arr[i]);printf("\n");}return 0;}

给几组测试数据:

82 1 3 3 2 2 1 31121 331 2 332 1 3

下面是WIKI的解释和方法(详细见:http://en.wikipedia.org/wiki/Dutch_national_flag_problem):

这个问题可以被看出是一个数组排序问题。假设每一个元素都可以被归为1、2、3(小,中,大) 三类当中的一个。  算法就是将属于每一类的元素归到相应的类,1类在2类前面,3类在2类后面。算法记录3个位置:最大类的下限,最小类的上限,中间类的上限。

如果当前元素属于大类,将该元素与大类下限后的一个元素交换。q--

如果当前元素属于小类,将该元素与小类上限上的一个元素交换。p++

如果属于中类,不处理.

下面是算法

#include <iostream>#include<stdlib.h>#include<stdio.h>#include<string.h>using namespace std;void swap(int *a, int *b){int tmp=*a;*a=*b;*b=tmp;}void three_way_partition(int *a,int size){int p=-1;int q=size;for(int i=0;i<q;){if(a[i]==1){swap(a[i],a[++p]);i++;}else if(a[i]==3){swap(a[i],a[--q]);}elsei++;}}int main(){int n,i;while(scanf("%d",&n)!=EOF){//input total numbersint *arr=new int[n];for(i=0;i<n;i++){scanf("%d",&arr[i]);//only 1,2,3 three colorsif(arr[i]>3||arr[i]<1){printf("Invalid\n");return 0;}}three_way_partition(arr,n);for(i=0;i<n;i++)printf("%d ",arr[i]);printf("\n");}return 0;}



原创粉丝点击