问题描述:
三色旗问题是一个经典的算法问题,问题本身不难,提出者是图算法中开山鼻祖Dijkstra. 问题的描述是:在一个随机的包含white, blue, red三种颜色的序列{0...k}中(三种颜色的数目相同),设计一个算法,使得该序列中的颜色按照red->white->blue的顺序周期排列。
1)从问题本身直接解法出发,最直观的算法是:
a)按照red->white->blue的顺序,依次对每个位置进行匹配
b)遍历序列{0...k},在每个位置上,看当前位置m是否为期望的颜色,如果是则跳出循环,查找下一个。如果不是期望的颜色,则从下一个位置开始,依次查找{m+1...k}找到一个期望颜色的位置n,然后交换m,n的值
c)这个算法的时间复杂度是O(n²)
代码片段如下:
UINT32 search_color(UINT32 start_index, COLOR_TYPE color)
{
UINT32 i;
if ((color >= COLOR_BUTT)||(start_index >= color_array.size()))
{
return NULL_LONG;
}
for (i=start_index; i<color_array.size(); i++)
{
if (color_array.at(i) == color)
{
break;
}
}
return i;
}
void tradational_solution()
{
UINT32 element_num;
element_num = (UINT32)color_array.size();
if (element_num == 0)
{
return;
}
UINT32 white, blue, red, i;
UINT32 expect_next_color=COLOR_RED;
for (i=0; i<element_num; i++)
{
switch(expect_next_color)
{
case COLOR_RED:
if (color_array[i] != COLOR_RED)
{
red = search_color(i+1, COLOR_RED);
swap(color_array[i], color_array[red]);
}
expect_next_color = COLOR_WHITE;
break;
case COLOR_WHITE:
if (color_array[i] != COLOR_WHITE)
{
white = search_color(i+1, COLOR_WHITE);
swap(color_array[i], color_array[white]);
}
expect_next_color = COLOR_BLUE;
break;
case COLOR_BLUE:
if (color_array[i] != COLOR_BLUE)
{
blue = search_color(i+1, COLOR_BLUE);
swap(color_array[i], color_array[blue]);
}
expect_next_color = COLOR_RED;
break;
default:
break;
}
print_array();
}
}
2)观察上述的算法,可以发现,第二次遍历{m+1...k}的目的是查找一个目标颜色的位置,这个操作需要O(n)复杂度操作。如果我们遍历一次{0...k}序列,然后建立三个颜色的队列,每个队列中保存该颜色的所有位置,那么在查找目标颜色时,我们只需要经过O(1)次操作就可以获取到该位置。这样总的复杂度为O(n)+O(n)*O(1)=O(n)次就可以完整所有的排序。
void update_queue(UINT32 add_index, COLOR_TYPE color)
{
switch(color)
{
case COLOR_RED:
que_r.pop();
que_r.push(add_index);
break;
case COLOR_WHITE:
que_w.pop();
que_w.push(add_index);
break;
case COLOR_BLUE:
que_b.pop();
que_b.push(add_index);
break;
default:
break;
}
}
void high_perf_solution()
{
UINT32 element_num, i;
element_num = (UINT32)color_array.size();
if (element_num == 0)
{
return;
}
//build queues of tree colors
for (i=0; i<element_num; i++)
{
switch(color_array[i])
{
case COLOR_RED:
que_r.push(i);
break;
case COLOR_WHITE:
que_w.push(i);
break;
case COLOR_BLUE:
que_b.push(i);
break;
default:
break;
}
}
//traverse the array
UINT32 white, blue, red;
UINT32 expect_next_color=COLOR_RED;
for (i=0; i<element_num; i++)
{
switch(expect_next_color)
{
case COLOR_RED:
if (color_array[i] != COLOR_RED)
{
red = que_r.front();
update_queue(red, color_array[i]);
swap(color_array[i], color_array[red]);
}
que_r.pop();
expect_next_color = COLOR_WHITE;
break;
case COLOR_WHITE:
if (color_array[i] != COLOR_WHITE)
{
white = que_w.front();
update_queue(white, color_array[i]);
swap(color_array[i], color_array[white]);
}
que_w.pop();
expect_next_color = COLOR_BLUE;
break;
case COLOR_BLUE:
if (color_array[i] != COLOR_BLUE)
{
blue = que_b.front();
update_queue(blue, color_array[i]);
swap(color_array[i], color_array[blue]);
}
que_b.pop();
expect_next_color = COLOR_RED;
break;
default:
break;
}
//cout<<i<<" "<<color_array[i]<<" ";
print_array();
}
}
对一个30000个的随机序列排序结果,两张算法比较如下:
附完整的代码如下:
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <time.h>
using namespace std;
typedef enum
{
COLOR_WHITE = 0,
COLOR_BLUE,
COLOR_RED,
COLOR_BUTT
}COLOR_TYPE;
typedef unsigned int UINT32;
#define NULL_LONG 0xFFFFFFFF
class TriColor
{
public:
TriColor()
{
UINT32 color=0;
for (UINT32 i=0; i<30000; i++)
{
color_array.push_back((COLOR_TYPE)color);
color = (color+1)%COLOR_BUTT;
}
random_shuffle(color_array.begin(), color_array.end());
print_array();
}
void print_array()
{
//for (UINT32 i=0; i<color_array.size(); i++)
//{
// switch(color_array[i])
// {
// case COLOR_RED:
// cout<<"R ";
// break;
// case COLOR_WHITE:
// cout<<"W ";
// break;
// case COLOR_BLUE:
// cout<<"B ";
// break;
// default:
// break;
// }
//}
//cout<<endl;
}
UINT32 search_color(UINT32 start_index, COLOR_TYPE color)
{
UINT32 i;
if ((color >= COLOR_BUTT)||(start_index >= color_array.size()))
{
return NULL_LONG;
}
for (i=start_index; i<color_array.size(); i++)
{
if (color_array.at(i) == color)
{
break;
}
}
return i;
}
void tradational_solution()
{
UINT32 element_num;
element_num = (UINT32)color_array.size();
if (element_num == 0)
{
return;
}
UINT32 white, blue, red, i;
UINT32 expect_next_color=COLOR_RED;
for (i=0; i<element_num; i++)
{
switch(expect_next_color)
{
case COLOR_RED:
if (color_array[i] != COLOR_RED)
{
red = search_color(i+1, COLOR_RED);
swap(color_array[i], color_array[red]);
}
expect_next_color = COLOR_WHITE;
break;
case COLOR_WHITE:
if (color_array[i] != COLOR_WHITE)
{
white = search_color(i+1, COLOR_WHITE);
swap(color_array[i], color_array[white]);
}
expect_next_color = COLOR_BLUE;
break;
case COLOR_BLUE:
if (color_array[i] != COLOR_BLUE)
{
blue = search_color(i+1, COLOR_BLUE);
swap(color_array[i], color_array[blue]);
}
expect_next_color = COLOR_RED;
break;
default:
break;
}
print_array();
}
}
void update_queue(UINT32 add_index, COLOR_TYPE color)
{
switch(color)
{
case COLOR_RED:
que_r.pop();
que_r.push(add_index);
break;
case COLOR_WHITE:
que_w.pop();
que_w.push(add_index);
break;
case COLOR_BLUE:
que_b.pop();
que_b.push(add_index);
break;
default:
break;
}
}
void high_perf_solution()
{
UINT32 element_num, i;
element_num = (UINT32)color_array.size();
if (element_num == 0)
{
return;
}
//build queues of tree colors
for (i=0; i<element_num; i++)
{
switch(color_array[i])
{
case COLOR_RED:
que_r.push(i);
break;
case COLOR_WHITE:
que_w.push(i);
break;
case COLOR_BLUE:
que_b.push(i);
break;
default:
break;
}
}
//traverse the array
UINT32 white, blue, red;
UINT32 expect_next_color=COLOR_RED;
for (i=0; i<element_num; i++)
{
switch(expect_next_color)
{
case COLOR_RED:
if (color_array[i] != COLOR_RED)
{
red = que_r.front();
update_queue(red, color_array[i]);
swap(color_array[i], color_array[red]);
}
que_r.pop();
expect_next_color = COLOR_WHITE;
break;
case COLOR_WHITE:
if (color_array[i] != COLOR_WHITE)
{
white = que_w.front();
update_queue(white, color_array[i]);
swap(color_array[i], color_array[white]);
}
que_w.pop();
expect_next_color = COLOR_BLUE;
break;
case COLOR_BLUE:
if (color_array[i] != COLOR_BLUE)
{
blue = que_b.front();
update_queue(blue, color_array[i]);
swap(color_array[i], color_array[blue]);
}
que_b.pop();
expect_next_color = COLOR_RED;
break;
default:
break;
}
//cout<<i<<" "<<color_array[i]<<" ";
print_array();
}
}
private:
vector<COLOR_TYPE> color_array;
queue<UINT32> que_w, que_r, que_b;
};
void main()
{
clock_t s_clock, e_clock;
TriColor tri_color = TriColor();
s_clock = clock();
tri_color.tradational_solution();
e_clock = clock();
cout<<"Algorithm1 cost "<<(e_clock-s_clock)*1000/CLOCKS_PER_SEC<<" micro seconds."<<endl;
s_clock = clock();
tri_color.high_perf_solution();
e_clock = clock();
cout<<"Algorithm2 cost "<<(e_clock-s_clock)*1000/CLOCKS_PER_SEC<<" micro seconds."<<endl;
}