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