【问题标题】:Priority Queue Issue优先队列问题
【发布时间】:2011-11-23 09:48:15
【问题描述】:

我正在根据本教程实现 A* 算法:

create the open list of nodes, initially containing only our starting node
   create the closed list of nodes, initially empty
   while (we have not reached our goal) {
       consider the best node in the open list (the node with the lowest f value)
       if (this node is the goal) {
           then we're done
       }
       else {
           move the current node to the closed list and consider all of its neighbors
           for (each neighbor) {
               if (this neighbor is in the closed list and our current g value is lower) {
                   update the neighbor with the new, lower, g value 
                   change the neighbor's parent to our current node
               }
               else if (this neighbor is in the open list and our current g value is lower) {
                   update the neighbor with the new, lower, g value 
                   change the neighbor's parent to our current node
               }
               else this neighbor is not in either the open or closed list {
                   add the neighbor to the open list and set its g value
               }
           }
       }
   }

现在我有两个优先队列用于打开列表和关闭列表。

将一个节点从打开列表移动到关闭列表后,我必须生成它的邻居,如果它们也在关闭列表中,则必须一一检查并执行上述操作。问题是我只能 peek() 仅队列的头部并与生成的邻居进行比较。我也无法访问队列中的其余节点以进行比较。

我的问题是:

如何将邻居与封闭列表中的节点进行比较。或者我应该为封闭列表使用不同的数据结构?

谢谢

【问题讨论】:

    标签: java algorithm path-finding


    【解决方案1】:

    PriorityQueue 的主要缺点是它只保证“第一个元素是什么”,不保证任何其他元素[除了它们比第一个“更大”],所以找到一个元素是一个扩展操作。

    您可以使用TreeSet 来存储您的状态,然后查找元素将在O(logn) 时间完成,而不是O(n) PriorityQueue 提供。您可以使用first() 方法获取第一个 [lowest] 元素。要修改一个元素,您首先需要删除原始 [可能需要额外的 HashMap:State->value 来存储当前值],然后插入新节点及其修改后的值
    请注意,您可能必须为您的节点重写 equals()

    另请注意:虽然两者都是O(logn),但TreeSet 中的每个插入操作通常比PriorityQueue 中的等效操作要慢,因此如果您的问题不必重新打开状态,此解决方案实际上可能会更慢.但是,在一般情况下,由于寻道时间缩短,预计这会比替代方案更快。

    【讨论】:

      【解决方案2】:

      在每个节点上存储一个值,指示它是否在打开列表、关闭列表或无列表中,然后您不必通过列表来查看它是否存在。

      而且,正如其他人所指出的,您可能会从实现自己的堆中获得最佳结果,因为 java 的实现显然缺乏更新节点上键值的能力。

      【讨论】:

      • 效率极低。迭代器不会按顺序返回元素,因此您只能进行 O(n 平方) 比较。
      • 最好的选择是什么?
      • @EJP 列表的顺序如何相关?您似乎在暗示顺序在某种程度上很重要,但我认为任何涉及遍历列表的方法都是非常低效的。另一种方法见上文。
      • @EJP O(n^2) 从何而来?这是 O(n).. 你说的似乎没有任何意义。
      • @EJP 您可能想了解大 O 表示法,特别是在未排序数组中查找项目的复杂性:en.wikipedia.org/wiki/…
      【解决方案3】:

      您的搜索空间的结构是什么?如果它是通过网格的路径,则可以使用网格“按位置”查找节点。要更新 open-list 上“可能重新父节点”的 F 成本,您需要 Java 的标准 PriorityQueue 类不支持的操作(即 UpdateKey,并且节点必须知道它们在堆中的索引,以便 UpdateKey 可以找到它们),因此您必须滚动自己的堆(这相对容易)。

      【讨论】:

        猜你喜欢
        • 2014-05-09
        • 1970-01-01
        • 2021-11-18
        • 2020-05-22
        • 1970-01-01
        • 2015-03-12
        • 1970-01-01
        • 1970-01-01
        • 2017-04-11
        相关资源
        最近更新 更多