【问题标题】:Optimizing A-Star Algorithm优化 A-Star 算法
【发布时间】:2011-03-27 00:39:05
【问题描述】:

根据维基百科在here 的实现,我已经实现了 A* 算法 但是,在移动设备上运行太慢了。尽管它在台式计算机上运行良好,但我必须等待无数小时才能完成该功能。有什么办法可以优化算法吗?

这是实际代码

public DriveRoute findroute(routenode from, routenode to)
        {
            Dictionary<int, routenode> openlist = new Dictionary<int, routenode>();
            openlist.Add(from.nodeid, from);
            Dictionary<int, routenode> closedlist = new Dictionary<int, routenode>();
            Dictionary<int, double> gscores = new Dictionary<int, double>();
            gscores.Add(from.nodeid, 0);
            Dictionary<int, double> hscores = new Dictionary<int, double>();
            hscores.Add(from.nodeid, distanceForRouting(from.latlon, to.latlon));
            Dictionary<int, double> fscores = new Dictionary<int, double>();
            fscores.Add(from.nodeid, gscores[from.nodeid] + hscores[from.nodeid]);
            Dictionary<int, routenode> came_from = new Dictionary<int, routenode>();
            while (openlist.Values.Count > 0)
            {
                routenode x = getLowestFscore(openlist, fscores);
                if (x.latlon.Equals(to.latlon))
                {
                    return rebuildPathWay(came_from, to);
                }
                openlist.Remove(x.nodeid);
                closedlist.Add(x.nodeid, x);
                foreach (routearc arc in x.outgoingarcs)
                {
                    if (closedlist.Keys.Contains(arc.endnode))
                        continue;
                    double tentative_g_score = gscores[x.nodeid] + arc.time;
                    bool tentative_is_better = false;
                    if (!openlist.Keys.Contains(arc.endnode))
                    {
                        openlist.Add(arc.endnode, map.routenodes[arc.endnode]);
                        tentative_is_better = true;
                    }
                    else if (tentative_g_score < gscores[arc.endnode])
                    {
                        tentative_is_better = true;
                    }
                    if (tentative_is_better)
                    {
                        if (came_from.ContainsKey(arc.endnode))
                            came_from[arc.endnode] = x;
                        else
                            came_from.Add(arc.endnode, x);
                        gscores[arc.endnode] = tentative_g_score;
                        hscores[arc.endnode] = distanceForRouting(arc.endlatlon, to.latlon);
                        fscores[arc.endnode] = gscores[arc.endnode] + hscores[arc.endnode];
                    }
                }
            }
            return null;
        }

【问题讨论】:

  • 你分析过它吗?瓶颈似乎是什么?
  • 似乎 Dictionary 类和 getLowestFscore() 是瓶颈。 getLowestFscore 只是一个用于查找最低 FScore 的 for 循环。我应该用什么替换它们?
  • 您的移动设备似乎有太多数据无法处理。你有多少个节点?也许您应该将您在字典中使用的数据分解到最低限度。
  • 30,000!即使算法是线性的......

标签: c# routing navigation gps


【解决方案1】:

不看整个代码就很难给出任何提示,但我或许可以给出一些提示:

您对字典所做的主要操作是找到成本最低的东西。字典后面的数据结构应该针对这个操作进行优化。一个经典的数据结构将是一个堆(不是与 new/delete malloc/free 相关的东西,而是数据结构:http://en.wikipedia.org/wiki/Heap_%28data_structure%29

您会发现这种数据结构的子类型,例如斐波那契堆等。值得一试。在没有实现 A* 的情况下,我也会尝试使用 splay-tree(在 wiki 上进行搜索会获得成功)。

第二:你是否在算法运行期间插入和删除节点?如果是这样,请确保为自己构建一个预分配节点池并使用它而不是调用 new/delete 或 malloc/free。内存分配可能非常很慢。

【讨论】:

    【解决方案2】:

    您应该在优先级队列中缓存每个节点的分数。这样,您只需在每次需要新节点时从优先级队列中弹出第一个节点,而不必调用 getLowestFscore。 实现 PriorityQueue 时,只需使用 SortedDictionary&lt;int, List&lt;routenode&gt;&gt;。使用 SetDefault(参见 here 示例)让您的生活更轻松。

    另外,由于您在移动设备上遇到更多问题,这可能是内存问题。在这种情况下,您可能需要考虑使用有界 BeamSearch - 它不会每次都为您提供最佳结果,但它应该运行得更快。

    【讨论】:

    • 可能有这样一种情况,SortedDictionary的Key,也是一个路由的F,对于两条不同的路由最终可能相同。我考虑过使用 SortedList,但遇到了 Key-must-unique 规则的问题。
    【解决方案3】:

    你能并行化 for 循环吗?您是否正在使用具有多个内核的特定移动设备?如果是这样,请查看 Tasks.Parallel.For(....) 或 Foreach。

    另外,考虑缓存任何可以缓存的信息。

    您使用 A* 代替 Djikstra 算法的任何原因?

    【讨论】:

    • A* 和 Djikstra 几乎一样,只是它使用启发式算法跑得更快。
    • 如果有人在看,只需添加更多信息。 A* 算法通常比 Djikstra 更快,因为 A* 存在于知情搜索算法中。基本上,A* 被优化为“忽略”搜索树中没有希望的节点,因此它产生更快的结果。
    【解决方案4】:

    A* 是一种很好的启发式算法,但您可能也需要优化。

    我会做的优化是使用节点组而不是所有节点来找到“最佳”路径。假设您有 1,000 个城市,为什么不将它们组合在一起并在更全球范围内找到最佳路径,然后优化路径。

    我只尝试实现通常的 A*,但没有进行这种优化。你为什么不试试呢;)

    【讨论】:

    • 这是一个好主意。 ;) 当我有多个城市时,我会使用它 :) 目前,我只有一个城市。
    【解决方案5】:

    A* 的大部分优化都用于打开和关闭列表的实现。具体来说,有以下四种方法:添加、删除、获取最小值项以及查找属于特定节点的条目。就个人而言,我发现使用完整的二进制堆来构建打开列表将显着提高我的 A* 代码的速度,该代码是用 Python 创建的。希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-06
      • 1970-01-01
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多