2011-05-09 75 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