c# – 维基百科A *寻路算法需要花费大量时间

c# – 维基百科A *寻路算法需要花费大量时间,第1张

概述我已经在C#中成功实现了A * pathfinding,但它很慢,我不明白为什么.我甚至尝试不对openNodes列表进行排序,但它仍然是相同的. 地图是80×80,有10-11个节点. 我从Wikipedia那里拿了伪代码 这是我的实施: public static List<PGNode> Pathfind(PGMap mMap, PGNode mStart, PGNode mEnd) 我已经在C#中成功实现了A * pathfinding,但它很慢,我不明白为什么.我甚至尝试不对openNodes列表进行排序,但它仍然是相同的.

地图是80×80,有10-11个节点.

我从Wikipedia那里拿了伪代码

这是我的实施:

public static List<PGNode> Pathfind(pgmap mMap,PGNode mStart,PGNode mEnd)    {        mMap.ClearNodes();        mMap.GetTile(mStart.X,mStart.Y).Value = 0;        mMap.GetTile(mEnd.X,mEnd.Y).Value = 0;        List<PGNode> openNodes = new List<PGNode>();        List<PGNode> closednodes = new List<PGNode>();        List<PGNode> solutionNodes = new List<PGNode>();        mStart.G = 0;        mStart.H = GetManhattanHeuristic(mStart,mEnd);        solutionNodes.Add(mStart);        solutionNodes.Add(mEnd);        openNodes.Add(mStart); // 1) Add the starting square (or node) to the open List.        while (openNodes.Count > 0) // 2) Repeat the following:        {            openNodes.sort((p1,p2) => p1.F.Compareto(p2.F));            PGNode current = openNodes[0]; // a) We refer to this as the current square.)            if (current == mEnd)            {                while (current != null)                {                    solutionNodes.Add(current);                    current = current.Parent;                }                return solutionNodes;            }            openNodes.Remove(current);            closednodes.Add(current); // b) Switch it to the closed List.            List<PGNode> neighborNodes = current.GetNeighborNodes();            double cost = 0;            bool isCostBetter = false;            for (int i = 0; i < neighborNodes.Count; i++)            {                PGNode neighbor = neighborNodes[i];                cost = current.G + 10;                isCostBetter = false;                if (neighbor.Passable == false || closednodes.Contains(neighbor))                    continue; // If it is not walkable or if it is on the closed List,ignore it.                if (openNodes.Contains(neighbor) == false)                {                    openNodes.Add(neighbor); // If it isn’t on the open List,add it to the open List.                    isCostBetter = true;                }                else if (cost < neighbor.G)                {                    isCostBetter = true;                }                if (isCostBetter)                {                    neighbor.Parent = current; //  Make the current square the parent of this square.                     neighbor.G = cost;                    neighbor.H = GetManhattanHeuristic(current,neighbor);                }            }        }        return null;    }

这是我正在使用的启发式:

private static double GetManhattanHeuristic(PGNode mStart,PGNode mEnd)    {        return Math.Abs(mStart.X - mEnd.X) + Math.Abs(mStart.Y - mEnd.Y);    }

我究竟做错了什么?这是一整天我一直在看同样的代码.

@H_403_28@解决方法 首先,使用分析器.用工具告诉你什么是慢的;什么是慢的往往令人惊讶.并使用调试器.制作一个包含五个节点的地图,并在尝试查找路径时逐步执行代码的每一行.什么意外发生了?如果是这样,请弄清楚发生了什么.

其次,抛开你的性能问题,我认为你也有正确性问题.你能解释一下为什么你认为曼哈顿距离是一个合理的启发式算法吗?

(对于那些不熟悉度量标准的人来说,“曼哈顿距离”或“出租车距离”是指如果你住在一个网格上的城市,你必须经过的两点之间的距离.在东北方向14英里处,您必须向北行驶10英里,然后向东行驶10英里,总共行驶20英里.)

A *算法要求其正确性,启发式总是低估了在两点之间行进所需的实际距离.如果图中有任何“对角线快捷方式”街道,那么曼哈顿距离会过高估计这些路径上的距离,因此算法不一定会找到最短路径.

为什么你不使用欧氏距离作为你的启发式?

您是否尝试使用“始终为零”作为启发式算法?这保证是低估的. (这样做可以实现Dijkstra的算法.)

第三,你似乎在这个实现中进行了大量的排序.当然你可能正在使用优先级队列;这比分拣便宜很多.

第四,我在我的博客上实现了C#3中的A *,欢迎您使用;没有明示或暗示的保证,使用风险自负.

http://blogs.msdn.com/b/ericlippert/archive/tags/astar/

我的代码很简单;我的实现中的算法如下所示:

var closed = new HashSet<Node>();var queue = new PriorityQueue<double,Path<Node>>();queue.Enqueue(0,new Path<Node>(start));while (!queue.IsEmpty){    var path = queue.Dequeue();    if (closed.Contains(path.LastStep)) continue;    if (path.LastStep.Equals(destination)) return path;    closed.Add(path.LastStep);    foreach(Node n in path.LastStep.Neighbours)    {        double d = distance(path.LastStep,n);        var newPath = path.AddStep(n,d);        queue.Enqueue(newPath.TotalCost + estimate(n),newPath);    }}

我们的想法是保持路径的优先级队列;也就是说,路径队列始终能够以最小距离告诉您到目前为止的路径.然后我们检查一下我们是否已经到达目的地;如果是这样,我们就完成了.如果没有,那么我们根据他们(低于)到目标的估计距离排队一堆新路径.

第五,维基百科中的伪代码可以得到改进.事实上,我的实际代码在很多方面比伪代码更容易遵循,这表明伪代码中可能存在太多细节.

总结

以上是内存溢出为你收集整理的c# – 维基百科A *寻路算法需要花费大量时间全部内容,希望文章能够帮你解决c# – 维基百科A *寻路算法需要花费大量时间所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1225346.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-05
下一篇2022-06-05

发表评论

登录后才能评论

评论列表(0条)

    保存