代码改变世界

荷兰国旗问题的算法实现

2013-10-23 17:17  Ross Wang  阅读(1275)  评论(0编辑  收藏  举报

一个字符串只有‘R’、‘G’、‘B’组成,如何让所有的‘R’出现在前面,所有的‘G’在中间,所有的‘B’在最后。

要求:要求空间复杂度为O(1),只许遍历一遍字符串数组

之所以叫荷兰国旗,是因为我们可以将红白蓝三色小球想象成条状物,有序排列后正好组成荷兰国旗。如下图所示:

    

 

算法思路

1. 维护三个游标 headPos、currentPos 、tailPos

2. headPos 指向开始, tailPos 指向尾部,用于分别插入 R 、B

3. currentPos 用于遍历,当发现是R时,与前面的 headPos 指的对象交换,然后 headPos 后移;当发现是B时,与后面的 tailPos 指的对象交换,tailPos 前移,并对 currentPos  所指的新值运行这一步(递归)

4. 当 currentPos 与 tailPos 相遇后停止

 

完整代码:

#include<iostream>
#include<string>

/************************
遍历过程中遇到 B 时的处理逻辑,递归实现
currentPos               当前位置
tailPos                  动态尾部位置
headPos                  动态头部位置
************************/
void HandleB(const int &currentPos,int *tailPos,int *headPos,std::string *str)
{
    if((*str)[--(*tailPos)] == 'B')
    {
        if( currentPos == (*tailPos)-1)
            (*str)[currentPos] = 'B';
        else
            HandleB(currentPos,tailPos,headPos,str);
    }
    else
    {
        if((*str)[*tailPos] == 'R')
            (*str)[(*headPos)++] = 'R';
        (*str)[*tailPos] = 'B';
    }
}
int main()
{
    std::string str;

    //方便多次测试
    while(true)
    {
        str.clear();
        //获取测试数据
        std::cout << "Please input R G B string with random order...\n"
                  <<"Or input exit to quit." << std::endl ;
        std::cin >> str;
        if(str.empty() )
        {
            std::cout << "Input is empty.\n" << std::endl ;
            continue;
        }

        //判断是否退出
        else if(!strcmp(str.c_str(),"exit"))
            break;
        std::cout <<"Input str is: "<< str <<"\n\n"<< std::endl ;
        int headPos = 0, tailPos = str.size() ;

        //开始遍历比较
        for(int currentPos= 0; currentPos<tailPos ; currentPos++)
        {
            char  c = str[currentPos] ;
            if(c != 'R' && c != 'G' && c != 'B')
            {
                std::cout << "Invalid char: "<<c<< std::endl ;
                break;
            }
            //假设所有数据都是G
            str[currentPos] = 'G' ;
            if( c == 'R')
            {
                str[headPos++] = c ;
            }
            else if( c == 'B')
            {
                //如果这时动态尾部tailPos所指数据是B,就需要让tailPos再往前
                HandleB(currentPos,&tailPos,&headPos,&str);
            }
            std::cout <<"      "<< str << std::endl ;
        }
        std::cout <<"\n\nOrdered str is: "<< str << std::endl ;
    }
}