优先级队列 - 更新后面的密钥的效果

时间:2016-02-07 15:31:54

标签: java data-structures priority-queue a-star

我试图理解为什么我的A *搜索实现似乎工作正常,即使我似乎正在更新优先级队列背后的密钥。

在我的代表地图的类中,我有以下数据结构来保存地图中的所有节点(比如从文件加载)。

// maps a latitude/longitude to a node in the map
HashMap<GeographicPoint, MapNode> nodes;

为了实现A *搜索,我的MapNode类保持“距离开始的距离”和“距离目标的启发距离”属性。在搜索开始之前,我将地图中每个节点的距离初始化为无穷大。这一切都很好。

当调用aStarSearch函数时,我创建一个Prority Queue(PQ),如下所示:

PriorityQueue<MapNode> toExplore = new PriorityQueue<MapNode>();

现在,当我按如下方式将节点排入此PQ时:

toExplore.add(startNode);

请注意,我没有创建节点的新副本。我只是为原始节点创建了一个额外的引用并将其添加到PQ。

稍后,作为A *实现的一部分,当我重新计算和更新节点对象中的距离时,我使用指向同一原始节点的引用再次执行此操作。那么,PQ也引用了相同的原始节点,因此效果是我只是改变了PQ下的距离(即键)!

这对PQ来说不是好事。但一切仍然有效! - 这意味着我得到了正确的最短路径并且已经探索了正确数量的节点等。

从PQ正在使用的MapNode实现中提供相关部分可能很有用:

public class MapNode implements Comparable<MapNode> {

// the location of the intersection in the world
private GeographicPoint location;


// NOTE: Equals method is based on comparing actual geographic point. 
// Whereas compareTo based on distances. 
// This implies a.equals(b) and a.compareTo(b) == 0 will return different result. 
// Is this OK? 

@Override
public boolean equals(Object obj) { 
    return this.location.equals(obj);
} 

// NOTE: Equals method is based on comparing actual geographic point. 
// Whereas compareTo based on distances. 
// This implies a.equals(b) and a.compareTo(b) == 0 will return different result. 
// Is this OK? 

@Override
public int compareTo(MapNode other) {
    // Comparison based on priorities
    return Double.compare(this.getTotalEstimatedDistance(), 
                          other.getTotalEstimatedDistance());
}

问题:

  1. 我不明白当我出队时,Priority Queue如何能够给我正确的最高优先级节点。我正在弄它背后的钥匙。
  2. 我如何设计得更好,以至于我没有这种代码味道?
  3. 如果需要,我可以提供额外的代码片段,以便更好地理解。

1 个答案:

答案 0 :(得分:0)

  

我不明白当我出队时,Priority Queue如何能够为我提供正确的最高优先级节点。我正在弄它背后的钥匙。

虽然这是一个坏主意,但没有任何保证它会显示为一个问题。 PriorityQueue未针对所有条目(仅第一个)进行排序,因此更改另一个条目不一定是个问题。在删除之前尝试更改第一个。 ;)

  

我怎样才能更好地设计这个,以便我没有这种代码味道?

每当您更改有序集合中的元素(以某种可能改变其位置的方式)时,您必须将其删除,更改并重新添加以确保集合未被破坏。

Queue<MapNode> q = new PriorityQueue<>(
                               Comparator.comparing(MapNode::getTotalEstimatedDistance));