【问题标题】:Can someone explain PriorityQueue in this example to me?有人可以向我解释这个例子中的 PriorityQueue 吗?
【发布时间】:2018-09-26 04:50:16
【问题描述】:

我正在尝试学习如何使用 PriorityQueue,因为我以前从未使用过。这是我在 LeetCode 上找到的一个正在使用的示例,用于解决在字符串数组中查找前 K 个元素的问题

public List<String> topKFrequent(String[] words, int k) {
    Map<String, Integer> count = new HashMap();
    for (String word: words) {
        count.put(word, count.getOrDefault(word, 0) + 1);
    }
    PriorityQueue<String> heap = new PriorityQueue<String>(
            (w1, w2) -> count.get(w1).equals(count.get(w2)) ?
            w2.compareTo(w1) : count.get(w1) - count.get(w2) );

    for (String word: count.keySet()) {
        heap.offer(word);
        if (heap.size() > k) heap.poll();
    }

    List<String> ans = new ArrayList();
    while (!heap.isEmpty()) ans.add(heap.poll());
    Collections.reverse(ans);
    return ans;
}

更值得注意的是,我想知道这条线在做什么:

PriorityQueue<String> heap = new PriorityQueue<String>(
            (w1, w2) -> count.get(w1).equals(count.get(w2)) ?
            w2.compareTo(w1) : count.get(w1) - count.get(w2) );

有人可以用跛脚的术语解释这里发生了什么吗?有没有办法将比较器重写为常规的“if”语句?

感谢您的帮助。

【问题讨论】:

  • "如果计数相等,则按字母顺序比较,否则按计数比较"。

标签: java data-structures priority-queue


【解决方案1】:

构造函数中的表达式是lambda expression。因为Comparator是一个函数式接口,即只有一个抽象方法的接口,所以可以使用lambda表达式作为创建匿名类的简写。

在你的例子中,

new PriorityQueue<String>((w1, w2) -> count.get(w1).equals(count.get(w2)) ? w2.compareTo(w1) : count.get(w1) - count.get(w2));

在功能上等同于

new PriorityQueue<String>(new Comparator<String>() {
    public int compare(String w1, String w2) {
        return count.get(w1).equals(count.get(w2)) ? w2.compareTo(w1) : count.get(w1) - count.get(w2);
    }
});

这也与创建一个实现Comparator&lt;String&gt; 的单独类相同,并将该类的一个实例作为参数传递给PriorityQueue

至于将Comparator 写为 if 语句,简短的回答是,不。比较器必须是Comparator&lt;String&gt; 的实例。然而,也许同一个比较器的一个更容易理解的版本如下:

new PriorityQueue<String>((w1, w2) -> {
    if (count.get(w1).equals(count.get(w2))) { // If the counts of w1 and w2 are the same,
        return w2.compareTo(w1); // Then return the reverse lexicographical ordering of w1 and w2 (e.g. "Zebra" comes before "Apple")
    } else if (count.get(w1) < count.get(w2)) {
        return -1; // w1 comes before w2
    } else {
        return 1; // w1 comes after w2
    }
});

注意:“字典顺序”本质上是字母顺序,但基于 ASCII 码。如需更多信息,请参阅String#compareTo(String)

希望这会有所帮助!

【讨论】:

  • 我无法告诉你我是多么感谢你写出来。这是我在网上搜索数小时后找到的最佳解释。非常感谢。
  • 当然,很高兴我能帮上忙。
【解决方案2】:

您使用的PriorityQueue 构造函数声明为:

public PriorityQueue(Comparator<? super E> comparator)

它接受泛型类型参数的对象的比较器。 comparator构造函数参数描述为:

将用于对该优先级队列进行排序的比较器。如果为 null,则将使用元素的自然顺序。

在您的调用中,参数是一个lambda expression,它提供了实现Comparator&lt;String&gt;。大致相当于下面的匿名类:

PriorityQueue<String> heap2 = new PriorityQueue<String>(new Comparator<String>() {
    @Override
    public int compare(String w1, String w2) {

        if(count.get(w1).equals(count.get(w2))) {
            return w2.compareTo(w1);
        } else {
            return count.get(w1) - count.get(w2);
        }

        // can also just be (without the if/else above):
        //return count.get(w1).equals(count.get(w2)) ? w2.compareTo(w1) : count.get(w1) - count.get(w2);
    }
});

【讨论】:

    猜你喜欢
    • 2011-07-14
    • 2014-10-13
    • 2010-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    相关资源
    最近更新 更多