如果条目的值已存在于PQ中,如何增加该条目的值?

时间:2018-03-12 00:16:12

标签: heap priority-queue

我以这个问题为出发点:

Add Key and Value into an Priority Queue and Sort by Key in Java

我有类似的情况,我的POJO的PQ有两个重要的属性:键和值。

但是,在我向PQ添加新条目之前,首先我要检查PQ中是否已存在具有相同密钥的条目。在这种情况下,我希望增加其值。我该怎么做呢?

1 个答案:

答案 0 :(得分:1)

javadoc说明了这一点。

  

强烈建议,但并非严格要求(x.compareTo(y)== 0)==(x.equals(y))

但同样,这不是必要的。有必要覆盖方法public boolean equals(Object entry)以使方法contains()起作用,而不是声明方法public boolean equals(Entry entry)

你应该有equals()类似的。

@Override
public boolean equals(Object entry) {
    if (entry instanceof Entry) return this.key == ((Entry) entry).key;
    else return false;
}

另外要考虑的是,当对象已经存在于已排序/哈希的集合中时,对该对象进行变异是一个可怕的想法。这会导致奇怪的行为。我会告诉你一个例子。

在条目中使用toString()方法。

@Override
public String toString() {
    return String.format("{ %d, %d }", key, value);
}

使用此代码打印优先级队列。

PriorityQueue<Entry> queue = new PriorityQueue<>();
for (Entry data : entries) {
    Entry entry = new Entry(data.getKey(), data.getValue());
    if (queue.contains(entry)) {
        for (Entry current : queue) { // just for the example
            if (current.equals(entry)) {
                current.addToValue(entry.getValue());
            }
        }
    } else {
        queue.add(entry);
    }
}

while (!queue.isEmpty()) // print ordered
    System.out.println(queue.poll());

有了这些数据。

List<Entry> entries = Arrays.asList(
        new Entry(1, 4),
        new Entry(2, 3),
        new Entry(2, 5)
);

输出未正确排序{ 1, 4 }, { 2, 8 }而不是{ 2, 8 }, { 1, 4 },这是因为id为2的条目在添加到集合后会发生变异。

另一方面,有了这个数据

List<Entry> entries = Arrays.asList(
        new Entry(1, 4),
        new Entry(2, 8)
);

它打印输出正确排序{ 2, 8 }, { 1, 4 }

解决方案可以使用HashMap,然后使用TreeSet

Map<Integer, Integer> map = new HashMap<>();
for (Entry data : entries) { // here instead read from csv and create entry
    map.computeIfPresent(data.getKey(), (k, v) -> v + data.getValue()); // sum priorities
    map.putIfAbsent(data.getKey(), data.getValue()); // add when not exists
}

现在您有一个由键标识的映射并包含优先级的sumarized值,您可以使用TreeSet或PriorityQueue对条目进行排序。

您不需要使用自定义条目,您可以使用java Entry并将Comparator传递给TreeSet / PriorityQueue。

TreeSet<Map.Entry<Integer, Integer>> treeSet = new TreeSet<>((e1, e2) ->
        e2.getValue() - e1.getValue() != 0 ?
        e2.getValue() - e1.getValue() :
        e2.getKey() - e1.getKey());
treeSet.addAll(map.entrySet());
System.out.println(treeSet);

此比较器首先比较优先级,如果不同,则按照后代顺序返回-1或1。

如果优先级相同,则比较密钥,并返回-1或1(因为没有重复的密钥,因此不能执行0),并且密钥的顺序正在下降。