我试图使用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后,它起作用了。
答案 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
而言,该顺序是递增的(考虑到比较器)。