C++ c++;洪水填充算法最终错误

C++ c++;洪水填充算法最终错误,c++,algorithm,flood-fill,C++,Algorithm,Flood Fill,我的泛洪填充算法快完成了,但有一个小错误,我花了大约3个小时调试,但我似乎找不到它 注: 在阅读时,我使用0到15之间的数字来定义墙 1=顶部 2=对 4=底部 8=左 (因此13意味着顶部/底部/左侧墙在那里) 我的节目: 它读取字段数以计算最大的房间(因此,下面的所有内容都是一个循环,重复计算字段数) 然后得到房间的尺寸 现在在类字段中,它创建一个对象数组(单元格),用于存储周围的墙(从左到右向下向上),值小于16 现在我认为问题来了,通过std::cin读取值 然后当所有内容都被读入时,

我的泛洪填充算法快完成了,但有一个小错误,我花了大约3个小时调试,但我似乎找不到它

注: 在阅读时,我使用0到15之间的数字来定义墙

1=顶部 2=对 4=底部 8=左 (因此13意味着顶部/底部/左侧墙在那里)

我的节目:

  • 它读取字段数以计算最大的房间(因此,下面的所有内容都是一个循环,重复计算字段数)

  • 然后得到房间的尺寸

  • 现在在类字段中,它创建一个对象数组(单元格),用于存储周围的墙(从左到右向下向上),值小于16

  • 现在我认为问题来了,通过std::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;
}
//een simpele洪水填充
#包括
#包括
#包括
类单元{
私人:
int-kamer,值;
布尔左,右,上,下;
公众:
//建造师
Cell::Cell(){};
//功能
bool CanLeft(){return left;}
bool CanRight(){return right;}
bool CanDown(){return down;}
bool CanUp(){return up;}
int GetRoom(){return kamer;}
无效集控室(intx){kamer=x;}
void SetValue(intx,introom=0){value=x;
kamer=房间;
std::位集位(值);
如果(位[3])左=真;
否则左=假;
如果(位[2])向下=真;
else down=错误;
if(位[1])right=true;
否则正确=错误;
如果(位[0])向上=真;
else up=false;
}
};
类字段{
私人:
国际商会;
int-Y;
int X;
内部温度;
细胞操场[][1];
公众:
//建造师
字段::字段(int-SizeY,int-SizeX){
Y=SizeY;
X=SizeX;
细胞操场[SizeY-1][SizeX-1];
}
//创建二维阵列并填充它
void Get_输入(){
对于(int Yas=0;Yas>温度;
操场[Yas][Xas].设定值(温度);
}
} 
};  
void Start(){Mark(0,0,1);}
无效标记(整数y、整数x、整数nr){
标准::cout sizeY>>sizeX;
现场漫滩(sizeY、sizeX);
floodfield.Get_input();
floodfield.Start();

std::cout我没有太多时间处理代码,但我的第一印象是您没有标记(或者更确切地说,没有使用标记)在数组中每个访问的位置,使你在一个方向上移动,并且在处理另一个位置时,你返回到原来的正方形。考虑测试的顺序:左、右、上、下;以及从左上角开始:

你不能向左移动,但你可以向右移动。在第二个递归级别,你可以向左移动,回到第一个。然后你不能向左移动,但你可以向右移动,所以你可以回到第二个,从第二个递归级别,你可以无限地移动到第一个

在移动到下一个正方形之前,您必须将您的正方形标记为已访问,并检查您要移动到的正方形在当前运行中是否未被访问


分段错误是在耗尽堆栈后无限递归的结果。

<1-11-2017:NEW-VERSION;使用两个位图成功测试

我提出了我的C版本的泛洪填充算法,它不使用递归调用,只使用新点偏移量的队列,它在窗口上工作:Winnoff-(WinDimX,WinDimY)的双缓冲区:*VBuffer(屏幕或图像的副本),并且可以选择编写泛洪填充结果的掩码(*ExtraVBuff)。 ExtraVBuff必须在调用前填充0(如果不需要掩码,可以将ExtraVBuff设置为NULL);调用后使用它可以进行渐变泛光填充或其他绘画效果。NewFloodFill的工作原理是每像素32位,它是一个C函数。我在1991年重新发明了这个算法(我用Pascal编写了他的),但现在它在C中工作,每像素32位;也不使用任何函数调用,只在队列中的每个“pop”之后进行除法,并且从不溢出队列,如果它的大小正确(约为图像像素的1/4),它总是允许正确填充任何区域;我在测试程序之后在C函数(FFILL.C)之前显示(测试C):

#定义图像宽度1024
#定义图像高度768
#定义图像大小图像宽度*图像高度
#定义队列\最大图像\大小/4
typedef int T_Queue[队列最大值];
typedef int T_Image[图像大小];
新填海区(int X,
INTY,
int颜色,
int BuffDimX,
int WinOffS,
int WinDimX,
温迪国际酒店,
T_Image VBuffer,
T_Image ExtraVBuff,
T_队列(我的队列)
/*替换与第一个像素相邻且等于该像素的所有像素*/
/*
#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);
}