为什么 A* 算法的这种实现只使用一个队列?

问题描述 投票:0回答:1

我在网上找到了这个算法在python中的实现,并且它可以工作。它搜索从另一点出发到达某一点的最佳路径。这是代码:

from pyamaze import maze,agent,textLabel
from queue import PriorityQueue
def h(cell1,cell2):
    x1,y1=cell1
    x2,y2=cell2

    return abs(x1-x2) + abs(y1-y2)
def aStar(m):
    start=(m.rows,m.cols)
    g_score={cell:float('inf') for cell in m.grid}
    g_score[start]=0
    f_score={cell:float('inf') for cell in m.grid}
    f_score[start]=h(start,(1,1))

    open=PriorityQueue()
    open.put((h(start,(1,1)),h(start,(1,1)),start))
    aPath={}
    while not open.empty():
        currCell=open.get()[2]
        if currCell==(1,1):
            break
        for d in 'ESNW':
            if m.maze_map[currCell][d]==True:
                if d=='E':
                    childCell=(currCell[0],currCell[1]+1)
                if d=='W':
                    childCell=(currCell[0],currCell[1]-1)
                if d=='N':
                    childCell=(currCell[0]-1,currCell[1])
                if d=='S':
                    childCell=(currCell[0]+1,currCell[1])

                temp_g_score=g_score[currCell]+1
                temp_f_score=temp_g_score+h(childCell,(1,1))

                if temp_f_score < f_score[childCell]:
                    g_score[childCell]= temp_g_score
                    f_score[childCell]= temp_f_score
                    open.put((temp_f_score,h(childCell,(1,1)),childCell))
                    aPath[childCell]=currCell
    fwdPath={}
    cell=(1,1)
    while cell!=start:
        fwdPath[aPath[cell]]=cell
        cell=aPath[cell]
    return fwdPath

if __name__=='__main__':
    m=maze(5,5)
    m.CreateMaze()
    path=aStar(m)

    a=agent(m,footprints=True)
    m.tracePath({a:path})
    l=textLabel(m,'A Star Path Length',len(path)+1)

    m.run()

我对这段代码的疑问是为什么他只使用一个队列?优先级队列是OPEN队列,但是为什么他不使用CLOSED队列呢?因为在许多伪代码中我都找到了两者,并且它通常在条件中使用,例如在这个伪代码中

OPEN = priority queue containing START
CLOSED = empty set
while lowest rank in OPEN is not the GOAL:
  current = remove lowest rank item from OPEN
  add current to CLOSED
  for neighbors of current:
    cost = g(current) + movementcost(current, neighbor)
    if neighbor in OPEN and cost less than g(neighbor):
      remove neighbor from OPEN, because new path is better
    if neighbor in CLOSED and cost less than g(neighbor): ⁽²⁾
      remove neighbor from CLOSED
    if neighbor not in OPEN and neighbor not in CLOSED:
      set g(neighbor) to cost
      add neighbor to OPEN
      set priority queue rank to g(neighbor) + h(neighbor)
      set neighbor's parent to current
python a-star
1个回答
0
投票

首先,

CLOSED
不是一个队列,而是一个集合:要么有节点在其中,要么不在其中(没有优先级或其他顺序)。

该集合实际上已被第一个脚本中使用 infinity 所取代。通过用无穷大初始化,表明相应的节点尚未被访问。通过测试 OPEN 或 CLOSED 中的成员资格,在第二个脚本中发现了相同的“未访问”概念。不同之处在于,当当前计算的路径成本小于已知的路径成本时,第二个脚本“取消访问”节点,而第一个脚本直接进行此检查 - 依赖于所有成本都小于无穷大的事实。

所以最终归结为同一件事。

© www.soinside.com 2019 - 2024. All rights reserved.