【趣味算法】三色旗问题:传统解法及基于队列的更好性能解法

问题描述:

三色旗问题是一个经典的算法问题,问题本身不难,提出者是图算法中开山鼻祖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;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值