`PriorityQueue` 中的 `add` 和 `addAll` 行为不同,这是为啥呢?
Posted
技术标签:
【中文标题】`PriorityQueue` 中的 `add` 和 `addAll` 行为不同,这是为啥呢?【英文标题】:`add` and `addAll` from a `PriorityQueue` behave differently, why is this?`PriorityQueue` 中的 `add` 和 `addAll` 行为不同,这是为什么呢? 【发布时间】:2020-05-26 07:12:56 【问题描述】:在将元素从 PriorityQueue
传输到 ArrayList
时,我注意到 List.add
和 List.addAll
的行为不同。但我不知道为什么。
示例代码:
public static void main(String[] args)
PriorityQueue<String> heap = new PriorityQueue<>(Comparator.reverseOrder());
heap.add("a");
heap.add("aa");
heap.add("aaa");
ArrayList<String> listAddAll = new ArrayList<>();
listAddAll.addAll(heap);
System.out.println(listAddAll);
ArrayList<String> listAdd = new ArrayList<>();
while (!heap.isEmpty())
listAdd.add(heap.remove());
System.out.println(listAdd);
listAddAll
包含 [aaa, a, aa]
,而 listAdd
包含 [aaa, aa, a]
。我希望两者都是后者,因为这是比较器指定的顺序。
【问题讨论】:
对不起,我的错,看错了。 你观察到的不是add
和addAll
之间的区别,而是traversing the queue和反复调用remove()
之间的区别。
【参考方案1】:
因为ArrayList.addAll
被实现为像这样使用Collection.toArray
:
public boolean addAll(Collection<? extends E> c)
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
而PriorityQueue.toArray
只是底层数组的复制操作:
public Object[] toArray()
return Arrays.copyOf(queue, size);
因此,addAll
将根据队列元素的顺序将其插入到 queue
字段中,该字段是平衡二叉堆,将元素的顺序保留为树而不是列表。你得到的原始数组代表树而不是排序列表。
【讨论】:
以上是关于`PriorityQueue` 中的 `add` 和 `addAll` 行为不同,这是为啥呢?的主要内容,如果未能解决你的问题,请参考以下文章
Java Review - PriorityQueue源码解读