A *寻路缓慢

时间:2012-06-07 15:17:12

标签: c++ performance algorithm maze

我目前正致力于A *搜索算法。该算法只是解决文本文件迷宫。我知道A *算法应该能够很快找到完成。在没有墙壁的20x20迷宫中,我似乎需要花费6秒才能找到路径。它确实找到了正确的路径,它只需要永远这样做。

如果我知道代码的哪一部分是问题,我会发布,但我真的不知道出了什么问题。所以这是我使用的算法...

 while(!openList.empty()) {  
    visitedList.push_back(openList[index]);
    openList.erase(openList.begin() + index);

    if(currentCell->x_coor == goalCell->x_coor && currentCell->y_coor == goalCell->y_coor)          
    }
        FindBestPath(currentCell);
        break;
    }

    if(map[currentCell->x_coor+1][currentCell->y_coor] != wall)
    {
    openList.push_back(new SearchCell(currentCell->x_coor+1,currentCell->y_coor,currentCell));
    }
    if(map[currentCell->x_coor-1][currentCell->y_coor] != wall) 
    {
        openList.push_back(new SearchCell(currentCell->x_coor-1,currentCell->y_coor,currentCell));
    }
    if(map[currentCell->x_coor][currentCell->y_coor+1] != wall) 
    {
        openList.push_back(new SearchCell(currentCell->x_coor,currentCell->y_coor+1,currentCell));
    }
    if(map[currentCell->x_coor][currentCell->y_coor-1] != wall) 
    {
        openList.push_back(new SearchCell(currentCell->x_coor,currentCell->y_coor-1,currentCell));
    }

    for(int i=0;i<openList.size();i++) {
        openList[i]->G = openList[i]->parent->G + 1;
        openList[i]->H = openList[i]->ManHattenDistance(goalCell);
    }

    float bestF = 999999;
    index = -1;

    for(int i=0;i<openList.size();i++) {
        if(openList[i]->GetF() < bestF) {
            for(int n=0;n<visitedList.size();n++) {
                if(CheckVisited(openList[i])) {
                    bestF = openList[i]->GetF();
                    index = i;
                }
            }
        }
    }
    if(index >= 0) {
        currentCell = openList[index];
    }
}

我知道这段代码很乱并且不是最有效的方法,但我认为它应该比它更快。任何帮助将不胜感激。

感谢。

4 个答案:

答案 0 :(得分:1)

你的20x20迷宫没有墙壁,因此很多很多路线长度相同。事实上,我估计有数万亿的等效路线。考虑到这一点,这似乎并不那么糟糕。

当然,由于你的启发式看起来很完美,你应该从排除启发式预测为精确的路线中获得很大的好处,只要到目前为止已知的最佳路线。 (如果你的启发式是正确的,这是安全的,即永远不要高估剩余的距离)。

答案 1 :(得分:1)

openList.erase是O(n),由于对for(int i=0;i<openList.size();i++)的调用,以CheckVisited开头的for循环为O(n ^ 2) - 每次迭代都会调用它们,使你的整体算法O(n ^ 3)。 A * 为O(n log n)。


尝试将openList更改为应该是的优先级队列,并将visitedList更改为哈希表。然后整个for循环可以替换为dequeue - 确保在排队之前检查visitedList.Contains(node) 是否正确!

此外,每次迭代都不需要为每个节点重新计算ManHattenDistance,因为它永远不会改变。

答案 2 :(得分:1)

这是一个很大的暗示。

如果您找到同一个单元格的两条路径,您可以随时丢弃较长的路径。如果有平局,你可以扔掉第二个去那里。

如果你实现了这一点,没有其他优化,那么搜索将会变得非常快。

其次,如果当前单元格的长度加上启发式的长度超过当前单元格的长度加上任何其他节点的启发式,则A *算法应该只考虑回溯。如果你实现了,那么它应该直接找到一个路径并停止。为了方便您需要将路径存储在优先级队列中(通常使用堆实现),而不是向量。

答案 3 :(得分:0)

你不是经常回溯吗?

当当前最佳解决方案变得比另一个先前访问过的路线更差时,A *算法回溯。在你的情况下,由于没有墙,所有路线都很好,永远不会死(而且正如MSalters正确指出的那样,有几个)。当你迈出一步时,你的路线会比所有其他更短的路线变得更糟。

如果确实如此,这可能会占算法所用的时间。