Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python-加速星形寻路算法_Python_Algorithm_Performance_A Star - Fatal编程技术网

Python-加速星形寻路算法

Python-加速星形寻路算法,python,algorithm,performance,a-star,Python,Algorithm,Performance,A Star,我已经编写了我的第一个稍微复杂的算法,这是该算法的一个实现。我遵循了一些关于实现图的说明,这样一个字典就包含了所有节点,每个节点都链接在一起。现在,由于这是一个游戏的全部内容,每个节点实际上只是一个节点网格中的一块瓷砖,因此,我如何计算启发式以及偶尔对它们的引用 多亏了timeit,我知道我可以每秒成功运行这个函数一百多次。可以理解,这让我有点不安,这是没有任何其他'游戏的东西'正在进行,如图形或计算游戏逻辑。所以我很想看看你们中是否有人能加速我的算法,我对Cython或它的kin完全不熟悉,我

我已经编写了我的第一个稍微复杂的算法,这是该算法的一个实现。我遵循了一些关于实现图的说明,这样一个字典就包含了所有节点,每个节点都链接在一起。现在,由于这是一个游戏的全部内容,每个节点实际上只是一个节点网格中的一块瓷砖,因此,我如何计算启发式以及偶尔对它们的引用

多亏了timeit,我知道我可以每秒成功运行这个函数一百多次。可以理解,这让我有点不安,这是没有任何其他'游戏的东西'正在进行,如图形或计算游戏逻辑。所以我很想看看你们中是否有人能加速我的算法,我对Cython或它的kin完全不熟悉,我无法编写一行C

不用再多说了,这是我的A星函数

def aStar(self, graph, current, end):
    openList = []
    closedList = []
    path = []

    def retracePath(c):
        path.insert(0,c)
        if c.parent == None:
            return
        retracePath(c.parent)

    openList.append(current)
    while len(openList) is not 0:
        current = min(openList, key=lambda inst:inst.H)
        if current == end:
            return retracePath(current)
        openList.remove(current)
        closedList.append(current)
        for tile in graph[current]:
            if tile not in closedList:
                tile.H = (abs(end.x-tile.x)+abs(end.y-tile.y))*10 
                if tile not in openList:
                    openList.append(tile)
                tile.parent = current
    return path

一种简单的优化方法是使用集合而不是列表来表示开放集和封闭集

openSet   = set()
closedSet = set()

这将使中的所有
不在测试中的所有
都变成O(1)而不是O(n)。

如上所述,将
关闭设置成一组

我尝试将
openList
编码为堆
import heapq

import heapq

def aStar(self, graph, current, end):
    closedList = set()
    path = []

    def retracePath(c):
        path.insert(0,c)
        if c.parent == None:
            return
        retracePath(c.parent)

    openList = [(-1, current)]
    heapq.heapify(openList)
    while openList:
        score, current = openList.heappop()
        if current == end:
            return retracePath(current)
        closedList.add(current)
        for tile in graph[current]:
            if tile not in closedList:
                tile.H = (abs(end.x-tile.x)+abs(end.y-tile.y))*10 
                if tile not in openList:
                    openList.heappush((tile.H, tile))
                tile.parent = current
    return path
但是,如果平铺不在openList中,您仍然需要在
中搜索,因此我会这样做:

def aStar(self, graph, current, end):
    openList = set()
    closedList = set()

    def retracePath(c):
        def parentgen(c):
             while c:
                 yield c
                 c = c.parent
        result = [element for element in parentgen(c)]
        result.reverse()
        return result

    openList.add(current)
    while openList:
        current = sorted(openList, key=lambda inst:inst.H)[0]
        if current == end:
            return retracePath(current)
        openList.remove(current)
        closedList.add(current)
        for tile in graph[current]:
            if tile not in closedList:
                tile.H = (abs(end.x-tile.x)+abs(end.y-tile.y))*10 
                openList.add(tile)
                tile.parent = current
    return []

我会像前面所说的那样使用集合,但我也会使用堆来查找最小元素(下一个
当前
)。这需要同时保留一个openSet和一个openHeap,但是内存应该不是问题。另外,在O(1)中设置insert,在O(log N)中设置HEAP,这样它们会很快。唯一的问题是heapq模块并没有真正使用按键。就我个人而言,我会修改它以使用键。这应该不会很难。或者,您可以在堆中使用(tile.H,tile)的元组

此外,我将遵循aaronasterling使用迭代而不是递归的思想,但同时,我将在
path
的末尾附加元素,并在末尾反转
path
。原因是在列表的第0位插入一个项目非常慢(我相信是O(N)),而如果我回忆正确的话,追加是O(1)。该部分的最终代码为:

def retracePath(c):
    path = [c]
    while c.parent is not None:
        c = c.parent
        path.append(c)
    path.reverse()
    return path
我将返回路径放在末尾,因为它似乎应该来自您的代码

下面是使用集合、堆等的最终代码:

import heapq


def aStar(graph, current, end):
    openSet = set()
    openHeap = []
    closedSet = set()

    def retracePath(c):
        path = [c]
        while c.parent is not None:
            c = c.parent
            path.append(c)
        path.reverse()
        return path

    openSet.add(current)
    openHeap.append((0, current))
    while openSet:
        current = heapq.heappop(openHeap)[1]
        if current == end:
            return retracePath(current)
        openSet.remove(current)
        closedSet.add(current)
        for tile in graph[current]:
            if tile not in closedSet:
                tile.H = (abs(end.x - tile.x)+abs(end.y-tile.y))*10
                if tile not in openSet:
                    openSet.add(tile)
                    heapq.heappush(openHeap, (tile.H, tile))
                tile.parent = current
    return []

而len(openList)不是0:
让我畏缩<代码>而openlist:
也一样。行
返回retracePath(current)
是不正确的(我想),你应该调用
retracePath(current)
,然后
返回路径
当前如果找到了结束节点,它将返回
@hughdbrown,是的,你不是唯一想到它的人(在寻路方面相当标准). 我确实看到您也想到了它,但实际上我没有查看您的实现。就我个人而言,我认为应该使用堆,并且应该使用属性来标记分幅,以指示每个分幅是否已被访问,而不是使用集合。但是,如果不这样做,我同时使用集合和堆的实现将是最有意义的。此外,如果他计划在这些分片上(不同的分片之间)执行多次运行,那么他必须在每次运行后重置访问属性。我不明白堆是如何工作的:行
heapq.heappush((tile.H,tile))
不应该是
heapq.heappush(openHeap,(tile.H,tile))
?!是的,你说得很对。我不确定我是怎么错过的,但我发布这篇文章已经快一年了。是的,但我有这个“问题”,你的解决方案引起了我的注意。谢谢你的回复。我确实修复了它,所以我希望答案有帮助。谢谢约翰,第二次你快速给出了一个有用的答案。我已经实现了下面的heapq建议,但它使用的集合确实减少了大部分时间(几乎三分之一!)。