簡體   English   中英

為什么此泛洪填充算法會導致堆棧溢出?

[英]Why does this flood-fill algorithm cause a stack overflow?

void FloodFill(int layer, int x, int y, int target, int replacement)
{
    if (x < 0) return;
    if (y < 0) return;
    if (x >= _mapWidth) return;
    if (y >= _mapHeight) return;

    if (_mapLayers[layer, x, y] != target) return;

    _mapLayers[layer, x, y] = replacement;

    FloodFill(layer, x - 1, y, target, replacement);
    FloodFill(layer, x + 1, y, target, replacement);
    FloodFill(layer, x, y - 1, target, replacement);
    FloodFill(layer, x, y + 1, target, replacement);

    return;
}

到目前為止,這是我的代碼,但是當它到達映射的末尾時,會導致堆棧溢出,是否有人知道如何解決該問題(可能是棘手的情況)?

請注意,此調用路徑存在:

(x, y) -> (x+1, y) -> (x+1-1, y) -> (x+1-1+1, y) -> ...

這是無限遞歸,因此您有堆棧溢出。 您的支票無法處理。 您必須執行一項額外的檢查:

if (_mapLayers[layer, x, y] == replacement) return;

即使您已包括上面的額外檢查,請注意,最大遞歸深度為(_mapWidth * _mapHeight) ,即使對於較小的位圖(例如100 x 100),該深度也可能非常深。

首先,您應該確保target!=replacement (可以在初始調用“ FloodFill”之前完成一次)。 然后,只要_mapWidth和_mapHeight不是很大(您的算法很大程度上取決於_mapLayers數組的內容),您的算法就可以工作。 如果這是一個問題,則應嘗試使用非遞歸算法。 創建一個

class Point
{ 
    public int x, y;
    public Point(int newX, int newY)
    {
         x=newX;
         y=newY;
    }
}

和一個

 List<Point> pointList;

將初始點放入此列表中並運行某種循環,直到pointList為空:從列表中取出一個點,像上面一樣進行處理,而不是上面的原始遞歸調用將四個鄰居再次放入列表中。

編輯:這是完整的示例,雖然沒有測試,但是:

    void FloodFill2(int layer, int xStart, int yStart, int target, int replacement)
    {
        if(target==replacement)
            return;
        List<Point> pointList = new List<Point>();

        pointList.Add(new Point(xStart,yStart));
        while(pointList.Count>0)
        {
            Point p = pointList[pointList.Count-1];
            pointList.RemoveAt(pointList.Count-1);
            if (p.x < 0) continue;
            if (p.y < 0) continue;
            if (p.x >= _mapWidth) continue;
            if (p.y >= _mapHeight) continue;
            if (_mapLayers[layer, p.x, p.y] != target) continue;
            _mapLayers[layer, p.x, p.y] = replacement;

            pointList.Add(new Point(p.x - 1, p.y));
            pointList.Add(new Point(p.x + 1, p.y));
            pointList.Add(new Point(p.x, p.y - 1));
            pointList.Add(new Point(p.x, p.y + 1));
        }
    }

EDIT2:實際上,這是優化例程的建議:如果插入變得毫無意義,請避免插入列表,因此:

            if(p.x>=0) 
                 pointList.Add(new Point(p.x - 1, p.y));
            if(p.x<_mapWidth-1) 
                 pointList.Add(new Point(p.x + 1, p.y));
            if(p.y>=0) 
                 pointList.Add(new Point(p.x, p.y - 1));
            if(p.y<_mapHeight-1) 
                 pointList.Add(new Point(p.x, p.y + 1));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM