我的洪水填充算法已接近完成,但某处出现了一个小错误,我花了大约3个小时调试,但我似乎无法找到它!
请注意: 在读入时,我使用0到15之间的数字来定义墙
1 =顶部 2 =对 4 =底部 8 =离开 (所以13意味着顶部/底部/左侧墙壁都在那里)
我的计划:
它读取的字段数量来计算最大的房间(因此这里的所有内容都是针对字段数重复的循环)。
然后它获得房间的尺寸
现在在类字段中,它创建了一个对象数组(Cell),用于存储墙(左下向上)和低于16的值
现在我认为问题来了,通过std :: cin读取值
然后当所有内容被读入时,它会扫描为空(0),然后创建一个房间,并检查它周围的可用空间(使用墙检查)
最后它返回最大值,我们就完成了。
我使用的输入:
1
2 2
13 3
15 14
所以会发生什么事情是在某个地方,在墙上检查,或者是对象的创建Cell出了问题(我认为)
这是我的剧本,很遗憾不得不问这样傻事!
提前致谢
// 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;
}
答案 0 :(得分:1)
我没有太多时间来处理代码,但我的第一印象是你没有在数组中标记(或者更确切地说不使用标记)每个访问位置,以便你向一个方向移动,同时处理您返回原始方块的其他位置。考虑一下测试顺序:左,右,上,下;并且你从左上角开始:
你不能向左移动,但你可以向右移动。在第二个递归级别,您可以向左移动并返回到第一个递归。然后你不能向左移动,但是你可以向右移动,所以你回到方形二,你从那里移动到一个方向......无穷无尽。
在您移动到下一个方格之前,您必须将您的方格标记为已访问,并检查您当前运行中是否未访问过您要移动的方格。
在您耗尽堆栈后,分段错误是无限递归的结果。
答案 1 :(得分:0)
1-11-2017:NEW-VERSION;成功测试了两个BITMAPS。
我提出了我的C版Flood-Fill算法,该算法不使用递归调用,而只是新点的偏移队列,它在窗口上工作:WinnOffs-(WinDimX,WinDimY)双缓冲:* VBuffer(屏幕或图像的副本),并且可选地,它写入泛洪填充结果的掩码(* ExtraVBuff)。 在调用之前必须用0填充ExtraVBuff(如果你不需要掩码,你可以设置ExtraVBuff = NULL);在通话后使用它你可以做渐变式填充或其他绘画效果。 NewFloodFill的每像素32位工作,它是一个C函数。我在1991年重新编写了这个算法(我用他的Pascal写的),但现在它在C中工作,每像素32位;也没有使用任何函数调用,只是在队列中每次“弹出”之后只进行一次除法,并且永远不会溢出队列,如果它以正确的方式调整大小(大约是图像的1/4像素),它允许总是要正确填写任何区域;我在c函数(FFILL.C)之前显示,在测试程序(TEST.C)之后:
#define IMAGE_WIDTH 1024
#define IMAGE_HEIGHT 768
#define IMAGE_SIZE IMAGE_WIDTH*IMAGE_HEIGHT
#define QUEUE_MAX IMAGE_SIZE/4
typedef int T_Queue[QUEUE_MAX];
typedef int T_Image[IMAGE_SIZE];
void NewFloodFill(int X,
int Y,
int Color,
int BuffDimX,
int WinOffS,
int WinDimX,
int WinDimY,
T_Image VBuffer,
T_Image ExtraVBuff,
T_Queue MyQueue)
/* Replaces all pixels adjacent to the first pixel and equal to this; */
/* if ExtraVBuff == NULL writes to *VBuffer (eg BUFFER of 786432 Pixel),*/
/* otherwise prepare a mask by writing on *ExtraVBuff (such BUFFER must */
/* always have the same size as *VBuffer (it must be initialized to 0)).*/
/* X,Y: Point coordinates' of origin of the flood-fill. */
/* WinOffS: Writing start offset on *VBuffer and *ExtraVBuff. */
/* BuffDimX: Width, in number of Pixel (int), of each buffer. */
/* WinDimX: Width, in number of Pixel (int), of the window. */
/* Color: New color that replace all_Pixel == origin's_point. */
/* WinDimY: Height, in number of Pixel (int), of the window. */
/* VBuffer: Pointer to the primary buffer. */
/* ExtraVBuff: Pointer to the mask buffer (can be = NULL). */
/* MyQueue: Pointer to the queue, containing the new-points' offsets*/
{
int VBuffCurrOffs=WinOffS+X+Y*BuffDimX;
int PixelIn=VBuffer[VBuffCurrOffs];
int QueuePnt=0;
int *TempAddr=((ExtraVBuff) ? ExtraVBuff : VBuffer);
int TempOffs1;
int TempX1;
int TempX2;
char FLAG;
if (0<=X && X<WinDimX && 0<=Y && Y<WinDimY) do
{
/* Fill to left the current line */
TempX2=X;
while (X>=0 && PixelIn==VBuffer[VBuffCurrOffs])
{
TempAddr[VBuffCurrOffs--]=Color;
--X;
}
TempOffs1=VBuffCurrOffs+1;
TempX1=X+1;
/* Fill to right the current line */
VBuffCurrOffs+=TempX2-X;
X=TempX2;
while (X+1<WinDimX && PixelIn==VBuffer[VBuffCurrOffs+1])
{
++X;
TempAddr[++VBuffCurrOffs]=Color;
}
TempX2=X;
/* Backward scan of the previous line; puts new points offset in Queue[] */
if (Y>0)
{
FLAG=1;
VBuffCurrOffs-=BuffDimX;
while (X-->=TempX1)
{
if (PixelIn!=VBuffer[VBuffCurrOffs] ||
ExtraVBuff && Color==ExtraVBuff[VBuffCurrOffs])
FLAG=1;
else
if (FLAG)
{
FLAG=0;
if (QueuePnt<QUEUE_MAX)
MyQueue[QueuePnt++]=VBuffCurrOffs;
}
--VBuffCurrOffs;
}
}
/* Forward scan of the next line; puts new points offset in Queue[] */
if (Y<WinDimY-1)
{
FLAG=1;
VBuffCurrOffs=TempOffs1+BuffDimX;
X=TempX1;
while (X++<=TempX2)
{
if (PixelIn!=VBuffer[VBuffCurrOffs] ||
ExtraVBuff && Color==ExtraVBuff[VBuffCurrOffs])
FLAG=1;
else
if (FLAG)
{
FLAG=0;
if (QueuePnt<QUEUE_MAX)
MyQueue[QueuePnt++]=VBuffCurrOffs;
}
++VBuffCurrOffs;
}
}
/* Gets a new point offset from Queue[] */
if (--QueuePnt>=0)
{
VBuffCurrOffs=MyQueue[QueuePnt];
TempOffs1=VBuffCurrOffs-WinOffS;
X=TempOffs1%BuffDimX;
Y=TempOffs1/BuffDimX;
}
/* Repeat the main cycle until the Queue[] is not empty */
} while (QueuePnt>=0);
}
这里有测试程序:
#include <stdio.h>
#include <malloc.h>
#include "ffill.c"
#define RED_COL 0xFFFF0000
#define WIN_LEFT 52
#define WIN_TOP 48
#define WIN_WIDTH 920
#define WIN_HEIGHT 672
#define START_LEFT 0
#define START_TOP 671
#define BMP_HEADER_SIZE 54
typedef char T_Image_Header[BMP_HEADER_SIZE];
void main(void)
{
T_Image_Header bmpheader;
T_Image *image;
T_Image *mask;
T_Queue *MyQueue;
FILE *stream;
char *filename1="ffill1.bmp";
char *filename2="ffill2.bmp";
char *filename3="ffill3.bmp";
int bwritten;
int bread;
image=malloc(sizeof(*image));
mask=malloc(sizeof(*mask));
MyQueue=malloc(sizeof(*MyQueue));
stream=fopen(filename1,"rb");
bread=fread(&bmpheader, 1, BMP_HEADER_SIZE, stream);
bread=fread((char *)image, 1, IMAGE_SIZE<<2, stream);
fclose(stream);
memset(mask,0,IMAGE_SIZE<<2);
NewFloodFill(START_LEFT,
START_TOP,
RED_COL,
IMAGE_WIDTH,
IMAGE_WIDTH*WIN_TOP+WIN_LEFT,
WIN_WIDTH,
WIN_HEIGHT,
*image,
NULL,
*MyQueue);
stream=fopen(filename2,"wb+");
bwritten=fwrite(&bmpheader, 1, BMP_HEADER_SIZE, stream);
bwritten=fwrite((char *)image, 1, IMAGE_SIZE<<2, stream);
fclose(stream);
stream=fopen(filename3,"wb+");
bwritten=fwrite(&bmpheader, 1, BMP_HEADER_SIZE, stream);
bwritten=fwrite((char *)mask, 1, IMAGE_SIZE<<2, stream);
fclose(stream);
free(MyQueue);
free(mask);
free(image);
}
我已经使用了,对于所显示的测试程序的输入,遵循Windows未压缩.BMP图像(ffill1.bmp):
通过所示的测试程序填写如下(ffill2.bmp):
使用“mask”而不是NULL,输出位图为(ffill3.bmp):