我应该如何为我的C ++程序实现泛洪填充功能?

时间:2018-11-11 09:04:15

标签: c++ vector flood-fill

我目前正在寻找类似这样的东西:

.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............

对此:

.............
.............
..XXX.....O..
..XXX.....O..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............

用户输入./a.exe input4.txt floodfill 2 10 o

我认为即时通讯将需要对程序实施某种递归,以便仅查看与用户指针匹配的索引(包括上,下,左和右的位置),而不是读取整个矢量(我不介意这样做,但不知道如何开始)。

这是我到目前为止用于洪水填充功能的代码:

void floodfilll(vector<vector<char>> &vec, int x, int y, char r, char dum)
{
 int ii; 
 ii = 0;
 int jj; 
 jj = 0;
for (int i = 0; i < vec.size(); i ++) {
        for (int j = 0; j < vec[i].size(); j++) {
            if (vec[i][j] == r) {
                vec[i][j] == r;
                if ((i + ii) > 0) {
                    if (vec[i-1][j] == r)
                        vec[i-1][j] = dum;
                        vec[i][j] == r;
                    ii--;
                    floodfilll(vec, x + ii, y, r, dum);
                }
                if ((j + jj) > 0) {
                    if(vec[i][j-1] != r)
                        vec[i][j-1] = dum;
                        vec[i][j] == r;
                    jj--;
                    floodfilll(vec, x, y + jj, r, dum);
                }
                if ((i + ii)<vec.size()) {
                    if (vec[i+1][j] != r)
                        vec[i+1][j] = dum;
                        vec[i][j] == r;
                    ii++;
                    floodfilll(vec, x + ii, y, r, dum);
                }
                if ((j + jj)<vec[i].size()) {
                    if (vec[i][j+1] != r)
                        vec[i][j+1] = dum;
                        vec[i][j] == r;
                    jj++;
                    floodfilll(vec, x, y + jj, r, dum);
                }
            }
        }
        replacee(vec, dum, r);
    }
}

注意:Im使用名为replacee的函数将Var dum替换为VarR。Vardum被分配为'i',而r为'X'。

此外,文本文件也被解析为char的 2d向量(char )**

这只是我程序其余部分的基础。这是替换功能:

    void replacee(vector<vector<char>> &vec, char oldd, char neww)
    {
        for (vector<char> &v : vec) // reference to innver vector
        {
            replace(v.begin(), v.end(), oldd, neww); // standard library algorithm
        }
    }

这是使用以下命令的int主文件:

int main(int argc, char* argv[]) {

fstream fin; char ch;
string name (argv[1]); //File Name.
vector<vector<char>> data;
// 2D Vector.
vector<char> temp;
// Temporary vector to be pushed 
// into vec, since its a vector of vectors.
fin.open(name.c_str(),ios::in);
// Assume name as an arbitary file.
string argument2 (argv[2]);
while(fin)
{
    ch = fin.get();
    if(ch!='\n') {
        temp.push_back(ch);
    }
    else 
    { 
        data.push_back(temp); 
        temp.clear(); 
    }
}
if (argument2 == "floodfill") {
    string argument3 (argv[3]);
    string argument4 (argv[4]);
    string argument5 (argv[5]);
    int x = 0;
    int y = 0;
    stringstream xx(argument3);
    stringstream yy(argument4);
    xx >> x;
    yy >> y;
    floodfilll(data, x, y, argument5[0], 'i');
    for (int m = 0; m < data.size(); m ++) {
        for (int n = 0; n < data[m].size(); n++) {
            cout << data[m][n];
        }
        cout << endl;
    }
}

fin.close();
} 

很抱歉,如果我只是粘贴代码以进行抓取,那么这是万一有人在我的思维方式之外有解决方案的情况。 int mainreplacee函数按预期工作。我只需要帮助,就可以使floodfilll正常工作。

这是我通过我的代码得到的输出:

$ ./a.exe input4.txt floodfill 2 10 o
.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............

2 个答案:

答案 0 :(得分:1)

为什么在每次递归中都要遍历整个字段?

通常,洪水填充的工作方式如下:

  1. 您有一个特定的起点。
  2. 您用所需的颜色填充了这个起点
  3. 您检查四个(如果您也考虑对角线)邻居中的每个邻居,如果它们的颜色与起点的颜色相同;如果是这样,您可以递归继续。

因此实现可能如下所示:

void floodfill
(
        std::vector<std::vector<char>>& v,
        unsigned int x, unsigned int y, char r
)
{
    char p = v[x][y];
    v[x][y] = r;
    if(x > 0 && v[x - 1][y] == p)
        floodfill(v, x - 1, y, r);
    if(x + 1 < v.size() && v[x + 1][y] == p)
        floodfill(v, x + 1, y, r);
    if(y > 0 && v[x][y - 1] == p)
        floodfill(v, x, y - 1, r);
    if(y + 1 < v[x].size() && v[x][y + 1] == p)
        floodfill(v, x, y + 1, r);
}

请注意,我没有检查要填充的颜色是否与起始像素相同,也没有先检查xy的范围检查。为了提高效率,我不会在递归函数中添加这些检查,而是在启动递归的特定输入函数中添加这些检查,因此它们仅在需要时执行一次,而不必重复执行。

答案 1 :(得分:0)

一个选择是使用递归,如另一个答案所建议。但是,就我个人而言,我更喜欢在不必要的地方避免递归。一种替代方法是基于队列的方法。

void floodfill (std::vector<std::vector<char>>& v, unsigned int x, unsigned int y, char r) {
    char init = v[x][y];
    if (init == r) return; //We don't want to get caught in an endless loop. 
    if (x >= v.size() || y >= v[x].size) return; //Index out of bounds. 
    std::queue<std::pair<unsigned int, unsigned int>> q;
    q.push(std::make_pair(x, y)); //Push the initial position into the queue.
    v[x][y] = r; //Replace the initial point. 
    while (!q.empty()) {//Keep looking at relevant neighbours so long as there is something in the queue. 
        auto pt = q.top(); //Collect the first entry.
        q.pop(); //Remove it, we don't want to keep processing the same point. 
        //Now add neighbours if they match our initial point. 
        if(pt.first > 0 && v[pt.first - 1][pt.second] == init)
            q.push(std::make_pair(pt.first - 1, pt.second);
            v[pt.first - 1][pt.second] = r; //Replace the value here to avoid pushing the same point twice. 
        if(pt.first + 1 < v.size() && v[pt.first + 1][pt.second] == init)
            q.push(std::make_pair(pt.first + 1, pt.second);
            v[pt.first + 1][pt.second] = r;
        if(pt.second > 0 && v[pt.first][pt.second - 1] == init)
            q.push(std::make_pair(pt.first, pt.second - 1);
            v[pt.first][pt.second - 1] = r;
        if(pt.second + 1 < v[pt.first].size() && v[pt.first][pt.second + 1] == init)
            q.push(std::make_pair(pt.first, pt.second + 1);
            v[pt.first][pt.second + 1] = r;
    }
}

这为您提供了类似BFS的泛洪填充模式,而无需递归。或者,您也可以使用stack而不是queue,然后,填充将表现得更像DFS(与递归模式将更相似)。鉴于数据结构更简单,它甚至可能比队列更好。

相关问题