荷兰国旗算法及其拓展

一排木桶里分别装有红白蓝三色小球(分别用0,1,2表示),如何让所有的'0'出现在前面,所有的'1'在中间,所有的'2'在最后。
要求:要求空间复杂度为O(1),只许遍历一遍字符串数组。 
之所以叫荷兰国旗,是因为我们可以将红白蓝三色小球想象成条状物,有序排列后正好组成荷兰国旗。
该算法的精髓在于把元素分为3个区域,只需扫描一次,通过交换元素,就能把元素放到该去的区域。 

我们可以把该算法扩展到将COLORNUM个不同颜色的小球(数字)按顺序归类,只需要不断地把左右边界往中间移动就行。 

#include <iostream>
#include <cstdlib>

using namespace std;

void Sort(int lib[], int libLen, int color[], int colorLen);
void TheDutchFlag(int lib[], int &left, int &right, int min, int max);
void Swap(int &a, int &b);

int main()
{
	const int COLORNUM = 19;
	int color[COLORNUM] = {0};
	
	for (int i=0; i<COLORNUM; i++) //为不同颜色赋值 
	{
		color[i] = i;
	}
	
	const int MAXSIZE = 140;
	int lib[MAXSIZE] = {0};
	
	for (int i=0; i<MAXSIZE; i++)
	{
		lib[i] = rand() % COLORNUM;
	}
	
	for (int i=0; i<MAXSIZE; i++)
	{
		cout << lib[i] << " ";
	}
	cout << endl;

   Sort(lib, MAXSIZE, color, COLORNUM);
	
	for (int i=0; i<MAXSIZE; i++)
	{
		cout << lib[i] << " ";
	}
	cout << endl;
    
    return 0;
}

void Swap(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}

void Sort(int lib[], int libLen, int color[], int colorLen)//将COLORNUM个不同颜色的小球(数字)按顺序归类
{
	int left = 0;
	int right = libLen - 1;
	int min = 0;
	int max = colorLen - 1;
	
	while (min < max && left < right)
	{
		if (min == max - 1) //只有两个不同元素,直接交换即可
		{
			while (left < right)
			{
				while (lib[left] == color[min]) //确定左边界的位置 
				{
					left++;
				}
				
				while (lib[right] == color[max]) //确定右边界的位置 
				{
					right--;
				}
				
				if (left < right)
				{
					Swap(lib[left++], lib[right--]);
				}
			}
		} 
		else //有超过2个不同元素,先把最大值和最小值分别放到左右区域,其他元素放在中间区域 
		{
			TheDutchFlag(lib, left, right, color[min], color[max]);
		}
		//处理中间的区域的元素,重新设置最大值和最小值 
		min++;
		max--;
	}
}

void TheDutchFlag(int lib[], int &left, int &right, int min, int max)
{
	while (lib[left] == min) //确定左边界的位置 
	{
		left++;
	}
		
	while (lib[right] == max) //确定右边界的位置 
	{
		right--;
	}
		
	int i = left;
	while (i <= right)
	{
		if (lib[i] == min) //是最小值,则与左区域的元素交换,同时左边界右移,游标也右移 
		{
			Swap(lib[i++], lib[left++]);
		}
		else if (lib[i] == max) //是最大值,则与右区域的元素交换,同时右边界左移,游标不动 
		{
			Swap(lib[i], lib[right--]);
		}
		else //既不是最大值也不是最小值,则该元素属于中间区域,不做任何交换,游标右移 
		{
			i++;
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值