なぜスタックオーバーフロー原因このフラッドフィルアルゴリズムのでしょうか?

StackOverflow https://stackoverflow.com/questions/2081274

  •  21-09-2019
  •  | 
  •  

質問

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) -> ...
あなたは、スタックオーバーフローを持っているので、

これは、無限再帰です。あなたのチェックは、これに対処することはできません。あなたが1つの余分なチェックを実行する必要があります:

if (_mapLayers[layer, x, y] == replacement) return;
<時間>

あなたは上記の余分なチェックが含まれている場合でも、最大の再帰の深さが小さくても、ビットマップのために非常に深いことができ(_mapWidth * _mapHeight)、あることに注意してください(例えば100×100)。

他のヒント

まず第一に、あなたは必ずtarget!=replacementが(「FLOODFILL」のinital呼び出し前に一度行うことができる)ことを確認する必要があります。次に、あなたのALGOは限り_mapWidthと_mapHeightが(それはあなたの_mapLayers配列の内容に大きく依存します)大特別でないとして、動作する可能性があります。これが問題である場合は、非再帰的なアルゴリズムを試してみてください。

を作成します。
class Point
{ 
    public int x, y;
    public Point(int newX, int newY)
    {
         x=newX;
         y=newY;
    }
}

 List<Point> pointList;

このリストに初期点を入れて、pointListが空になるまでループのいくつかの種類を実行します。リストに再び4人の隣人を入れて上に上記の代わりに、オリジナルの再帰呼び出しのようにそれを処理し、リストのうちの一点を取ります。

編集:ここでは完全な例である、けれども、それをテストしませんでした。

    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帰属
所属していません StackOverflow
scroll top