c++ Floodfill 算法最终错误
我的洪水填充算法快完成了,但是某个地方有一个小错误,我花了大约3个小时调试,但我似乎找不到它!
笔记: 读入时我使用 0 到 15 的数字来定义墙壁
1 = 顶部 2 = 右 4 = 底部 8 = 左 (所以 13 意味着顶部/底部/左侧的墙壁在那里)
我的程序:
-
它读取字段数来计算最大的房间(所以下面的所有内容都是一个循环,重复字段数)。
-
然后它获取房间的尺寸
现在在类字段中,它创建一个对象数组(Cell),用于存储周围的墙壁(左右下上),并且低于 16 的值
现在这里是我认为问题来了,通过读取值std::cin
-
读取值,然后当读入所有内容时,它会扫描空(0),然后创建一个房间,并检查其周围的可用空间(使用 wall-check)
-
最后返回最大值,我们就完成了。
我使用的输入:
1
2 2
13 3
15 14
所以发生的情况是,在某个地方,在墙壁检查中,或者创建对象单元出了问题(我认为)
这是我的脚本,很抱歉不得不问这样的愚蠢问题!
提前致谢
// een simpele floodfill
#include <stdlib.h>
#include <iostream>
#include <bitset>
class Cell {
private:
int kamer, value;
bool left, right, up, down;
public:
// constructor
Cell::Cell() {};
// functions
bool CanLeft() { return left ; }
bool CanRight() { return right; }
bool CanDown() { return down ; }
bool CanUp() { return up ; }
int GetRoom() { return kamer; }
void SetRoom(int x) { kamer = x ; }
void SetValue(int x, int room=0) { value = x;
kamer = room;
std::bitset<sizeof(int)> bits(value);
if (bits[3]) left = true;
else left = false;
if (bits[2]) down = true;
else down = false;
if (bits[1]) right = true;
else right = false;
if (bits[0]) up = true;
else up = false;
}
};
class Field {
private:
int Biggest_Chamber;
int Y;
int X;
int temp;
Cell playfield[][1];
public:
// constructor
Field::Field(int SizeY, int SizeX) {
Y = SizeY;
X = SizeX;
Cell playfield[SizeY-1][SizeX-1];
}
// Create a 2d array and fill it
void Get_input() {
for (int Yas = 0; Yas < Y; Yas++){
for (int Xas = 0; Xas < X; Xas++){
std::cin >> temp;
playfield[Yas][Xas].SetValue(temp);
}
}
};
void Start() { Mark(0,0,1); }
void Mark(int y, int x, int nr) {
std::cout << nr;
temp = nr;
playfield[y][x].SetRoom(nr);
if (playfield[y][x].CanLeft()) {
if (playfield[y][x-1].GetRoom() != 0) {
Mark(y, x-1, nr);
std::cout << nr;
system("pause");}}
if (playfield[y][x].CanDown()) {
if (playfield[y+1][x].GetRoom() != 0) {
Mark(y+1, x, nr);
std::cout << nr;
system("pause");}}
if (playfield[y][x].CanRight()) {
if (playfield[y][x+1].GetRoom() != 0) {
Mark(y, x+1, nr);
std::cout << nr;
system("pause");}}
if (playfield[y][x].CanUp()) {
if (playfield[y-1][x].GetRoom() != 0) {
Mark(y-1, x, nr);
std::cout << nr;
system("pause");}}
for (int vertical = 0; vertical < Y; vertical++) {
for (int horizontal = 0; horizontal < X; horizontal++) {
if (playfield[vertical][horizontal].GetRoom() == 0) Mark(vertical, horizontal, nr+1);
}
}
}
int MaxValue() {
int counter[temp];
int max = 0;
for (int y = 0; y < Y; y++) {
for (int x = 0; x < X; x++) {
counter[playfield[y][x].GetRoom()]++;
}
}
for (int i = 0; i < temp; i++)
{
if (counter[i] > max)
max = counter[i];
}
return max;
}
};
int main() {
using namespace std;
int NrKamers;
int sizeY;
int sizeX;
std::cin >> NrKamers;
for (int i = 0; i < NrKamers; i++){
std::cin >> sizeY >> sizeX;
Field floodfield(sizeY, sizeX);
floodfield.Get_input();
floodfield.Start();
std::cout << floodfield.MaxValue() << std::endl;
}
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我没有太多时间来处理代码,但我的第一印象是您没有标记(或者更确切地说不使用标记)数组中的每个访问位置,以便您朝一个方向移动,并在处理另一个方向时位置你回到原来的方块。考虑测试的顺序:左、右、上、下;并且从左上角开始:
您不能向左移动,但可以向右移动。在第二个递归级别,您可以向左移动并返回到第一个方块。然后你不能向左移动,但你可以向右移动,所以你回到方格二,从那里你移动到方格一......无限。
在移动到下一个方格之前,您必须将您的方格标记为已访问,并检查您打算移动到的方格在当前运行中尚未被访问过。
分段错误是耗尽堆栈后无限递归的结果。
I have not had much time to deal with the code, but my first impression is that you are not marking (or rather not using the mark) each visited position in the array, so that you move in one direction, and while processing that other position you return back to the original square. Consider that the sequence of tests where: left, right, up, down; and that you start in the top-left corner:
You cannot move left, but you can move right. At that second recursion level you can move left and go back to square one. Then you cannot move left, but you can move right, so you go back to square two, from which you move to square one... infinitedly.
Before you move to the next square you have to mark your square as visited, and also check that the square you intend to move to has not been visited in the current run.
The segmentation fault is the result of infinite recursion, after you exhaust the stack.
2017 年 1 月 11 日:新版本;已成功测试两个位图。
我提出了我的 C 版本的 Flood-Fill 算法,它不使用递归调用,而仅使用新点偏移量的队列,它在窗口上工作:双缓冲区的 WinnOffs-(WinDimX,WinDimY) :*VBuffer(屏幕或图像的副本),并且可以选择写入洪水填充结果的掩码(*ExtraVBuffer)。
调用前ExtraVBuff必须填0(如果不需要掩码可以设置ExtraVBuff= NULL);在调用后使用它,您可以进行渐变填充或其他绘画效果。 NewFloodFill 适用于每像素 32 位,它是一个 C 函数。我在 1991 年重新发明了这个算法(我用 Pascal 编写了他的算法),但现在它可以在 C 语言中运行,每像素 32 位;也不使用任何函数调用,只在每次从队列中“弹出”后进行除法,并且永远不会溢出队列,如果它的大小正确(大约图像像素的 1/4),它允许始终正确填充任何区域;我在 c 函数 (FFILL.C) 之前显示,在测试程序 (TEST.C) 之后显示:
这里是测试程序:
对于显示的测试程序的输入,我使用了以下 Windows 未压缩的 .BMP图片 (ffill1.bmp):
填充,由所示测试程序填充,如下(ffill2.bmp):
使用“mask”而不是 NULL,输出位图是 (ffill3.bmp):
1-11-2017: NEW-VERSION; SUCCESFULLY TESTED WITH TWO BITMAPS.
I propose my C version of the Flood-Fill algorithm, which doesn't uses recursive calls, but only a queue of the offsets of the new points, it works on the window: WinnOffs-(WinDimX,WinDimY) of the double-buffer: *VBuffer (copy of the screen or image) and, optionally, it write a mask of the flood-fill's result (*ExtraVBuff).
ExtraVBuff must be filled it with 0 before the call (if you don't need a mask you may set ExtraVBuff= NULL); using it after call you can do gradient floodfill or other painting effects. NewFloodFill works with 32 Bit per Pixel and it is a C function. I've reinvented this algorithm in 1991 (I wrote his in Pascal), but now it works in C with 32 Bit per Pixel; also not uses any functions calls, does only a division after each "pop" from queue, and never overflows the queue, that, if it is sized in the right way (about 1/4 of the pixels of the image), it allows always to fill correctly any area; I show before the c-function (FFILL.C), after the test program (TEST.C):
Here there is the test program:
I've used, for the input of the test program shown, the follow Windows uncompressed .BMP image (ffill1.bmp):
Filled, by the test program shown, as follows (ffill2.bmp):
Using "mask" instead of NULL, the output bitmap is (ffill3.bmp):