2011-05-09 77 views
0

我的填充算法几乎完成,但有一个小错误,我花了大约3个小时的时间调试,但我似乎无法找到它!C++ Floodfill算法最终错误

注: 当我使用数字从0至15,以限定壁读取

1 =顶部 2 =右 4 =底部 8 =左 (所以13将意味着该顶/下/左墙是有)

我的计划:

  • 它读取字段数来计算(所以一切BEL空间最大这里的ow是一个重复的字段数量的循环)。

  • 然后它获取房间的尺寸

    在类字段
  • 现在,它创建的对象(细胞)的阵列,其存储所述壁围绕(左右向下向上),并且低于16

  • 的值
  • 现在,这里是我觉得问题就来了,通过阅读性病价值观:: CIN

  • ,然后在读的一切,它扫描空(0),然后创建一个房间,并检查为它周围的可用空间(使用墙壁检查)

  • 并在最后它返回最大值,我们完成了。

输入我用:

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; 
} 
+1

什么是错误讯息? 'class Field'已经有一个右大括号('};')。这是一个错字,你又在做同样的事情吗? – Mahesh 2011-05-09 07:56:23

+0

分段错误 - 但通过调试,我发现以某种方式在Markeer(int,int,int)中遇到无限循环,什么?在它后面的';'? – Buster 2011-05-09 07:57:33

+3

在发布之前将您的变量名称和评论翻译成英文会很有礼貌;并不是每个人都能理解荷兰语。 – 2011-05-09 08:09:58

回答

1

我没有太多的时间来处理的代码,但我的第一印象是,你是不是标志(或者不想使用该商标),每个访问数组位置中,以便您朝一个方向移动,并在处理另一个位置时返回原始方块。考虑一下测试的顺序:左,右,上,下;并且您从左上角开始:

您不能向左移动,但可以向右移动。在第二递归级别上,您可以向左移动并返回到第二个递归级别。然后你不能向左移动,但是你可以向右移动,所以你回到第二个方块,从中移动到第二个方块......无限地。

在您移动到下一个广场之前,您必须将您的广场标记为已访问,并且还要检查您打算移动到的广场在当前运行中还没有被访问过。

分段故障是在耗尽堆栈之后无限递归的结果。

+0

这可能是,但是在我的语义中,我已经在'playfield [y] [x] .setNr(nr)''中将这个单元的房间状态从0改变为nr,并且然后每当我想去做一个不同的单元格,我检查它是不是房间状态== 0, 但它可能很好,语法上说不同.. – Buster 2011-05-09 08:28:01

+0

它真的很难遵循,因为它是,你可能想要考虑在其他地方提供整个代码(ideone?),我没有在任何地方看到'setNr'方法。如果引用'setRoom(nr)',即修改内部'kamer'属性,但该属性不用于控制递归 – 2011-05-09 10:09:12

0

1-11-2017:NEW-VERSION;成功完成了两个BITMAPS测试。

我建议我的C版本的Flood-Fill算法,它不使用递归调用,但只有一个新点的偏移量的队列,它在窗口上工作:WinnOffs-(WinDimX,WinDimY)of双缓冲区:* VBuffer(屏幕或图像的副本),并且可选地,它写入洪水填充结果的掩码(* ExtraVBuff)。在调用之前ExtraVBuff必须用0填充(如果你不需要掩码,你可以设置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); 
} 

我已经使用,所示的测试程序的输入,则按照视窗未压缩.BMP图像(ffill1.bmp):

enter image description here

填充,由所示的测试程序,如下(ffill2.bmp):

enter image description here

使用,而不是NULL “面具” 时,输出位图(ffill3.bmp):

enter image description here