PriorityQueue(Java)的字符串排序问题

时间:2020-06-01 18:30:48

标签: java sorting comparator priority-queue

我试图使用PriorityQueue对字符串列表进行排序并删除重复项。最初,我使用PriorityQueue,它不会更改顺序。在我更改为TreeSet之后,它起作用了。但是,我想了解已定义比较器的优先级队列有什么问题。希望听到一些解释。

无效代码:

public class RemoveDuplicateStrings {
    public static ArrayList<String> removeDuplicates(List<String> input) {
        PriorityQueue<String> pq = new PriorityQueue<>((a, b) -> a.compareTo(b));

        for (String s : input) {
            if (!pq.contains(s)) {
                pq.add(s);
            }
        }
        return new ArrayList<String>(pq);
    }

    public static void main(String[] args) {
        List<String> output = removeDuplicates(List.of("Hey", "Hi", "Hello", "Hey", "Hello"));
        System.out.println(output);
    }
}

我得到的结果是: [Hello, Hi, Hey],正确的顺序应该是:你好,嘿,你好。

在我使用相同的Comparator将数据结构更改为TreeSet后,它起作用了。

1 个答案:

答案 0 :(得分:0)

您正在使用ArrayList constructor,它从作为参数传递的集合中复制元素,并在其上调用toArray方法。对于PriorityQueue,它仅复制基础数组,并且这些元素没有特定顺序。来自PriorityQueue::toArray文档:

返回一个包含此队列中所有元素的数组。 这些元素没有特定的顺序。

但是对于TreeSet::toArray(从AbstractCollection继承的实现):

返回一个包含此集合中所有元素的数组。 如果此集合保证其迭代器返回其元素的顺序,则此方法必须按相同顺序返回元素

实际上,TreeSet保证了由其迭代器返回的元素的顺序。来自TreeSet::iterator文档:

以升序返回此集合中元素的迭代器。

这就是为什么您得到这样的结果。要获得所需的内容,必须轮询队列以按比较器定义的顺序接收元素:

public static ArrayList<String> removeDuplicates(List<String> input) {
        PriorityQueue<String> pq = new PriorityQueue<>((a, b) -> a.compareTo(b));

        for (String s : input) {
            if (!pq.contains(s)) {
                pq.add(s);
            }
        }

        ArrayList<String> result = new ArrayList<>();
        while (!pq.isEmpty()) {
            result.add(pq.poll());
        }
        return result;
}

此处的关键是PriorityQueue的迭代器不会按垂直顺序返回元素,但是对于TreeSet而言,该顺序是递增的(考虑到比较器)。