【问题标题】:Priority Queue - Effect of updating keys behind its back优先级队列 - 背后更新密钥的效果
【发布时间】:2016-02-07 15:31:53
【问题描述】:

我试图了解为什么我的 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. 我不明白当我出列时优先级队列如何能够给我正确的最高优先级节点。我在弄乱它背后的钥匙。
  2. 我怎样才能更好地设计它以使我没有这种代码异味?

如果需要,我可以提供额外的 sn-ps 代码,以便更好地理解。

【问题讨论】:

  • 这里的行为是未定义的,可能看起来有效,但行为不可预测。更新优先级队列中的密钥很可能注定要失败。一个典型的 Java 实现只会用新键重新插入键,而不删除旧条目。

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


【解决方案1】:

我不明白优先级队列如何在我出列时为我提供正确的最高优先级节点。我在弄乱它背后的钥匙。

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

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

每当您更改有序集合中的元素(以可能会改变其位置的方式)时,您必须将其移除、更改并重新添加以确保集合不会损坏。

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

【讨论】:

    猜你喜欢
    • 2010-10-01
    • 2014-08-05
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    相关资源
    最近更新 更多