多次运行泛洪填充算法时遇到堆栈溢出异常

时间:2011-08-03 01:51:52

标签: c# .net algorithm windows-phone-7 xna

我有一个排列在网格上的对象列表。我想直接或通过他们的邻居删除任何没有返回到网格顶部的路径。

我认为这样做的好方法是首先使网格上的所有内容都删除,然后在顶行上创建任何内容都不可删除​​。然后,我想从顶行的任何对象进行泛洪填充,以使与它们连接的对象不可删除。

我想不出一种方法(有效)来优化它。有没有更简单的方法去做我想做的事情?

我可能通过使用列表而不是二维数组射击自己。它引入了许多额外的foreach循环。

    internal void DetectHangingObjects(int X)
    {
        //Set all objects to deletable
        for (int i = 0; i < planets.Count; i++)
            planets[i].deletable = true;

        //Set first row to not deletable
        for (int i = 0; i < planets.Count; i++)
        {
            Debug.WriteLine(planets[i].X + " " + X);

            if (planets[i].X == X) //X=0
            {
                planets[i].deletable = false;
                try
                {
                    DetectHangingNeighbours(planets[i]);
                }

                catch (Exception ee)
                { Debug.WriteLine(ee.Message); }
            }
        }          
    }

    internal void DetectHangingNeighbours(Planet planet)
    {
        if (planet == null || planet.deletable==true)
            return;

        planet.deletable = false;

        DetectHangingNeighbours(GetTopLeftNode2(planet));
        DetectHangingNeighbours(GetTopRightNode2(planet));
        DetectHangingNeighbours(GetLeftNode2(planet));
        DetectHangingNeighbours(GetRightNode2(planet));
        DetectHangingNeighbours(GetBottomLeftNode2(planet));
        DetectHangingNeighbours(GetBottomRightNode2(planet));
    }

    //The following methods check the six adjacent objects and returns them to the caller if they match
    internal Planet GetTopLeftNode2(Planet planet)
    {
        foreach (Planet gridPlanet in planets)
            if (gridPlanet.X == planet.X - planetSize && gridPlanet.Y == planet.Y - yOffset)
                return gridPlanet;

        return null;
    }

    internal Planet GetTopRightNode2(Planet planet)
    {
        foreach (Planet gridPlanet in planets)
            if (gridPlanet.X == planet.X - planetSize && gridPlanet.Y == planet.Y + yOffset)
                return gridPlanet;

        return null;
    }

    internal Planet GetLeftNode2(Planet planet)
    {
        foreach (Planet gridPlanet in planets)
            if (gridPlanet.X == planet.X && gridPlanet.Y == planet.Y - planetSize)
                return gridPlanet;

        return null;
    }

    internal Planet GetRightNode2(Planet planet)
    {
        foreach (Planet gridPlanet in planets)
            if (gridPlanet.X == planet.X && gridPlanet.Y == planet.Y + planetSize)
                return gridPlanet;

        return null;
    }

    internal Planet GetBottomLeftNode2(Planet planet)
    {
        foreach (Planet gridPlanet in planets)
            if (gridPlanet.X == planet.X + planetSize && gridPlanet.Y == planet.Y - yOffset)
                return gridPlanet;

        return null;
    }

    internal Planet GetBottomRightNode2(Planet planet)
    {
        foreach (Planet gridPlanet in planets)
            if (gridPlanet.X == planet.X + planetSize && gridPlanet.Y == planet.Y + yOffset)
                return gridPlanet;

        return null;
    }

2 个答案:

答案 0 :(得分:3)

解开递归

一个答案是解开你的递归。你得到一个堆栈溢出,因为有太多的递归级别需要内存分配才能完成并返回,因此“堆栈溢出”。

限制递归

我过去曾为XNA游戏创建了一个编辑器,我需要一个泛洪填充算法,我所做的就是在退出之前对其递归的次数设置一个上限。实际上,这意味着我可能不得不对未填充的剩余部分重新应用大量填充,但不会导致堆栈溢出。

洪水填充算法

这使用常规循环来避免堆栈溢出错误。

答案 1 :(得分:2)

避免递归(DetectHangingNeighbours调用自身)。使用堆栈方法代替:

push your starting node into the stack

while there are elements in stack...
  pop element from stack

  if the element is not visited
    visit the element
    push its neighbours into the stack
  end if
end while
祝你好运。