Java PriorityQueue在删除元素时更改顺序

Java PriorityQueue在删除元素时更改顺序,java,data-structures,priority-queue,Java,Data Structures,Priority Queue,在不提供自定义比较器的情况下,优先级队列按升序插入元素,但是,在删除特定元素后,顺序会发生更改 PriorityQueue pq=new PriorityQueue(); pq.增加(10); pq.增加(1); pq.增加(2); pq.增加(2); pq.移除(2); 用于(int x:pq){ 系统输出println(x); } //产出:1102,而不是预期的:1210 有什么想法吗 谢谢。不要像在集合/数组上那样迭代您的优先级队列;使用.poll(),而不是: while(pq.pe

在不提供自定义比较器的情况下,优先级队列按升序插入元素,但是,在删除特定元素后,顺序会发生更改

PriorityQueue pq=new PriorityQueue();
pq.增加(10);
pq.增加(1);
pq.增加(2);
pq.增加(2);
pq.移除(2);
用于(int x:pq){
系统输出println(x);
}
//产出:1102,而不是预期的:1210
有什么想法吗


谢谢。

不要像在集合/数组上那样迭代您的
优先级队列
;使用
.poll()
,而不是:

while(pq.peek()!=null){
System.out.println(pq.poll());
}
优先级队列是一种抽象数据类型,通常被实现为数据结构,而数据结构(通常)是通过数组实现的。 实现二进制堆还有其他一些方法,但普通数组是实现二进制堆的最快、最简单和最好的方法

数组如何表示二进制堆的示例如下:


在您的情况下,队列顺序没有更改;相反,您只是以错误的方式使用了数据结构,只是以传统的
迭代方式对每个
/迭代方式对其进行迭代,就像在基本数组上进行迭代一样,没有考虑到优先级队列支持数组没有按其第i个索引进行排序;相反,它将顶层元素保持在树的顶部(最小堆或最大堆大小写),您不能通过传统方式对其进行迭代来获得
.poll()
效果。

这是因为PriorityQueue是最小堆的实现(默认情况下在Java中),这意味着根元素将始终低于列表中的其他元素

以您的问题为例:

  • 在数组中插入10时,索引1处的元素为10
  • 插入1时,位置1处的元素现在为1,而位置10处的元素移到了索引2
  • 插入2时,如
    1<2
    所示,无需移动元素,2插入到索引3处
  • 当您插入2时,2将位于10下方,因为需要移位,2将插入到2处,10将隐藏到索引4中
  • 插入所有阵列后,请查看以下视频:

    array: [NULL, 1, 2, 2, 10]
    

    现在,当您删除2时,10需要移位,10被移回索引2,数组的状态是
    [NULL,1,10,2]
    ,这就是您迭代时看到的输出。此外,请检查PriorityQueue内部实现的,并且在未提供
    比较器时使用的

    private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }
    
    private void(int k,E x){
    
    比较有趣。即使使用迭代器,它也会显示为
    1102
    ,有什么原因可以解释输出与
    .poll()之间的差异吗
    ?请参阅我对问题的评论谢谢,这就解释了它!也许可以将该评论移到您的答案中?这是对所选实现的一个很好的解释,但真正的答案是PriorityQueue的公共文档回答了这个问题(无论所选的实现是什么):“方法迭代器()中提供的迭代器”不保证以任何特定顺序遍历优先级队列的元素。”另外,实际的存储阵列backing
    PriorityQueue
    本质上是一个堆/树结构。迭代该阵列(这就是增强型for each在此处的计算方式)将按元素的存储顺序迭代元素,而不是按元素在堆中的遍历方式迭代元素。因此,对于普通人来说,它本质上是一个“无序”数组。但这并不意味着队列相关方法(如
    #poll
    ,请参见下文)是无序的。答案就在javadoc for PriorityQueue中:“方法迭代器()中提供的迭代器不保证以任何特定顺序遍历优先级队列的元素。”