优化A-Star算法

时间:2010-08-08 19:11:13

标签: c# routing navigation gps

我根据维基百科在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;
        }

5 个答案:

答案 0 :(得分:3)

如果没有看到整个代码,很难给出任何提示,但我可能会给出一些提示:

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

你会发现像fibonacci-heaps这样的数据结构的子类型等等。值得尝试一下。如果没有实现A *我也会尝试使用splay-tree(在wiki上搜索会给你点击)。

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

另外,请考虑缓存您可以使用的任何信息。

你使用A *代替Djikstra算法的原因是什么?

答案 3 :(得分:0)

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

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

我只尝试实现通常的A *,但不是这个优化。你为什么不试试呢;)

答案 4 :(得分:0)

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