优先级队列问题

时间:2011-11-23 09:48:16

标签: java algorithm path-finding

基于本教程实现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
               }
           }
       }
   }

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

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

我的问题是:

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

感谢

3 个答案:

答案 0 :(得分:0)

在每个节点上存储一个值,指示它是否在打开列表,关闭列表或没有列表中,然后您不必浏览列表以查看它是否存在。

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

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

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