关于PriorityQueue优先级队列中元素是否有序的一个问题

PriorityQueue

PriorityQueue是基于堆实现的数据结构,其逻辑结构是一棵完全二叉树,存储结构其实是一个数组。
PriorityQueue,也叫优先级队列,它是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。
如果不提供Comparator的话,优先队列中元素默认按自然顺序排列,也就是数字默认是小的在队列头,字符串则按字典序排列。也就是说我们通过设置comparator比较器来定义优先级别。

疑问

先看这段代码:

public class A {
    public static void main(String[] args) {
        //设置队列的初始长度为10
        PriorityQueue<Integer> queue = new PriorityQueue<>(10);
        //入队
        for(int i=10;i>=5;i--)
            queue.offer(i);
        //遍历元素
        for(Integer i:queue)
            System.out.print(i+" ");
    }
}
//输出结果:5 7 6 10 8 9

正如上面所说,默认的comparator是按照自然顺序排列,而上面的例子,{10 9 8 7 6 5}数组的元素依次入队,但是出队的顺序却不是 5 6 7 8 9 10,这是为什么呢。

我的疑惑:队列里的元素不是有序的吗?

为什么输出的结果是 5 7 6 10 8 9,而不是 5 6 7 8 9 10???为什么输出结果不是有序的?

改成大顶堆却可以有序输出的:

public class A {
    public static void main(String[] args) {
        PriorityQueue<Integer> queue = new PriorityQueue<>(10, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
        for(int i=10;i>=5;i--)
            queue.offer(i);
        for(Integer i:queue)
            System.out.print(i+" ");
    }
}
//输出结果:10 9 8 7 6 5 

原因

仔细想了想小顶堆的结构,画一画上面例子的入队过程,总算明白为什么会输出那样的结果了:
小顶堆只是保证根节点不大于左右子节点。但是左右子节点谁大谁小并不能保证。
如果这样解释还是没能想明白,自己模拟一下{10,9,8,7,6,5}的入队过程就明白了。
也就是说,队列里的元素,在物理结构上是一个数组,是无序的。

如何让队列里的元素有序输出

队列在物理结构上是数组,是无序的。但是其逻辑结构,是小顶堆,是有序的。

通过poll方法让堆顶元素出列,然后会进行调整堆操作,调整之后,堆顶又是最小的元素。如此,一直出队,每次出队的都是当前堆里的最小元素(因为出队的是队头元素,而且是小顶堆,因此出队的肯定是最小元素),如此直至队列为空。就能让元素有序输出了。

代码实现:

public class A {
    public static void main(String[] args) {
        PriorityQueue<Integer> queue = new PriorityQueue<>(10);
        for(int i=10;i>=5;i--)
            queue.offer(i);
        //(此代码根上面代码的区别)通过出列的方式来遍历,而不是直接遍历
        while(queue.peek()!=null)
            System.out.print(queue.poll()+" ");
    }
}
//输出结果:5 6 7 8 9 10

想通之后,也就能想明白为什么上面将优先队列的堆通过自定义comparator比较器设置成大顶堆,不通过出列方式遍历而直接遍历元素,输出的结果就是10 9 8 7 6 5。

最后

其实就是一开始的理解错了。定义中说的明明是“每次从队列中取出的是具有最高优先权的元素。”想到了小顶堆,我就理解成了堆里的元素是有序的。

然而并不完全是。它只是在逻辑结构上是有序的,即根节点大于左右节点。但是从物理结构上看,数组是无序的。只有通过出列的方式遍历,才是有序的。

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java优先级队列可以通过以下方法来更新节点: 1. 删除节点:优先级队列可以使用 `remove()` 方法来删除特定节点。该方法依据节点的值来定位并删除元素。使用 `remove()` 方法时,会自动调整队列其他节点的位置以保持有序性。 2. 更新节点:要更新节点,首先需要找到该节点。可以使用 `Iterator` 迭代器遍历队列元素,并使用 `peek()` 方法来获取元素,然后通过比较节点的值来找到要更新的节点。一旦找到节点,可以使用 `remove()` 方法将其从队列删除,然后使用 `add()` 或 `offer()` 方法将更新后的节点重新插入队列。 以下是示例代码: ```java PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(); // 添加初始节点 priorityQueue.offer(3); priorityQueue.offer(1); priorityQueue.offer(4); priorityQueue.offer(2); // 输出优先级队列的初始状态 System.out.println("初始优先级队列: " + priorityQueue); // 更新节点 Iterator<Integer> iterator = priorityQueue.iterator(); while (iterator.hasNext()) { int value = iterator.next(); if (value == 2) { iterator.remove(); // 删除节点 break; } } priorityQueue.offer(5); // 添加更新节点 System.out.println("更新后的优先级队列: " + priorityQueue); ``` 输出结果为: ``` 初始优先级队列: [1, 2, 4, 3] 更新后的优先级队列: [1, 3, 4, 5] ``` 上述代码,我们首先将初始节点添加到优先级队列。然后使用迭代器遍历队列,找到要更新的节点(值为2),然后将该节点从队列删除。最后,将更新后的节点(值为5)重新插入队列。输出结果显示了更新后的优先级队列的内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值