当前位置: 首页> 房产> 建筑 > 临清建网站_东莞seo优化推广_湖南seo博客seo交流_网络推广推广培训

临清建网站_东莞seo优化推广_湖南seo博客seo交流_网络推广推广培训

时间:2025/7/12 21:35:01来源:https://blog.csdn.net/gaosw0521/article/details/143227656 浏览次数:0次
临清建网站_东莞seo优化推广_湖南seo博客seo交流_网络推广推广培训

1 PriorityQueue 简介

PriorityQueue 是 Java 中的一个基于优先级堆的优先队列实现,它能够在 O(log n) 的时间复杂度内实现元素的插入和删除操作,并且能够自动维护队列中元素的优先级顺序。与普通队列不同,PriorityQueue 不是先进先出的,而是按照元素的优先级进行排序。当你往 PriorityQueue 中插入一个元素时,它会自动根据元素的优先级将其插入到合适的位置。当你从 PriorityQueue 中删除一个元素时,它会自动将优先级最高的元素出队。

2 PriorityQueue 的使用

  • 创建 PriorityQueue 对象

    PriorityQueue<String> priorityQueue = new PriorityQueue<>();
    
  • 添加元素

    priorityQueue.offer("沉默王二");
    priorityQueue.offer("陈清扬");
    priorityQueue.offer("小转铃");
    
  • 遍历并打印元素

    while (!priorityQueue.isEmpty()) {System.out.print(priorityQueue.poll() + " ");
    }
    
  • 指定优先级顺序

    PriorityQueue<String> priorityQueue = new PriorityQueue<>(Comparator.reverseOrder());
    

3 PriorityQueue 的主要作用

PriorityQueue 的主要作用是维护一组数据的排序,使得取出数据时可以按照一定的优先级顺序进行。当我们调用 poll() 方法时,它会从队列的顶部弹出最高优先级的元素。它在任务调度、事件处理等场景中广泛应用,也常用于实现 Dijkstra 算法、Prim 算法、Huffman 编码等算法。

  • Dijkstra 算法:用于计算带权图中的最短路径。该算法采用贪心策略,在遍历图的过程中,每次选取当前到源点距离最短的一个顶点,并以它为中心进行扩展,更新其他顶点的距离值。经过多次扩展,可以得到源点到其它所有顶点的最短路径。

  • Prim 算法:用于求解最小生成树。该算法从任意一个顶点开始,逐渐扩展生成树的规模,每次选择一个距离已生成树最近的顶点加入到生成树中,使得生成树的所有边的权值之和最小。

  • Huffman 编码:一种基于霍夫曼树的压缩算法,用于将一个字符串转换为二进制编码以进行压缩。该算法通过建立霍夫曼树,将出现频率较高的字符用较短的编码表示,而出现频率较低的字符用较长的编码表示,从而实现对字符串的压缩。在解压缩时,根据编码逐步解析出原字符串。

4 PriorityQueue 的底层实现

PriorityQueue 的底层是基于堆(Heap)实现的。堆是一种完全二叉树,其中每个节点的值都小于或等于其子节点的值(小顶堆),或者每个节点的值都大于或等于其子节点的值(大顶堆)。堆的特点是根节点的值最小(小顶堆)或最大(大顶堆),并且任意非根节点 i 的值都不大于(或不小于)其父节点的值。

5 堆的存储结构

堆可以使用数组来存储,而不需要使用指针等额外的空间。假设节点下标为 i,则其父节点下标为 (i - 1) / 2,其左子节点下标为 2 * i + 1,其右子节点下标为 2 * i + 2

  • 完全二叉树

          1/   \2     3/ \   /4   5 6
    
  • 小顶堆

        1/ \2   3/ \ / \
    4  5 6  7
    
  • 大顶堆

         8/   \7     5/ \   / \
    6   4 2   1
    

6 方法剖析

6.1 add() 和 offer()

add(E e)offer(E e) 的语义相同,都是向优先队列中插入元素。区别在于,add() 在插入失败时会抛出异常,而 offer() 则会返回 false。对于 PriorityQueue,这两个方法的实现基本相同。

  • offer(E e)

    public boolean offer(E e) {if (e == null)throw new NullPointerException();modCount++;int i = size;if (i >= queue.length)grow(i + 1); // 自动扩容size = i + 1;if (i == 0)queue[0] = e; // 队列原来为空,插入第一个元素elsesiftUp(i, e); // 调整堆结构return true;
    }
    
  • siftUp(int k, E x)

    private void siftUp(int k, E x) {while (k > 0) {int parent = (k - 1) >>> 1; // 计算父节点下标Object e = queue[parent];if (comparator.compare(x, (E) e) >= 0)break;queue[k] = e;k = parent;}queue[k] = x;
    }
    

siftUp() 方法的作用是从指定位置 k 开始,将元素 x 逐层与父节点进行比较并交换,直到满足 x >= queue[parent] 为止。

6.2 element() 和 peek()

element()peek() 的语义完全相同,都是获取但不删除队首元素(即优先级最高的元素)。区别在于,element() 在队列为空时会抛出异常,而 peek() 则会返回 null

  • peek()
    public E peek() {if (size == 0)return null;return (E) queue[0]; // 返回堆顶元素
    }
    

6.3 remove() 和 poll()

remove()poll() 的语义也完全相同,都是获取并删除队首元素。区别在于,remove() 在队列为空时会抛出异常,而 poll() 则会返回 null

  • poll()

    public E poll() {if (size == 0)return null;int s = --size;modCount++;E result = (E) queue[0]; // 获取堆顶元素E x = (E) queue[s];queue[s] = null;if (s != 0)siftDown(0, x); // 调整堆结构return result;
    }
    
  • siftDown(int k, E x)

    private void siftDown(int k, E x) {int half = size >>> 1;while (k < half) {int child = (k << 1) + 1; // 计算左孩子下标Object c = queue[child];int right = child + 1;if (right < size && comparator.compare((E) c, (E) queue[right]) > 0)c = queue[child = right]; // 选择较小的孩子if (comparator.compare(x, (E) c) <= 0)break;queue[k] = c;k = child;}queue[k] = x;
    }
    

siftDown() 方法的作用是从指定位置 k 开始,将元素 x 逐层向下与左右孩子中较小的那个交换,直到满足 x <= queue[child] 为止。

6.4 remove(Object o)

remove(Object o) 方法用于删除队列中与指定对象 o 相等的元素(如果有多个相等,只删除一个)。该方法不是 Queue 接口内的方法,而是 Collection 接口的方法。

  • remove(Object o)
    public boolean remove(Object o) {int i = indexOf(o); // 查找元素下标if (i == -1)return false;int s = --size;if (s == i)queue[i] = null; // 删除最后一个元素else {E moved = (E) queue[s];queue[s] = null;siftDown(i, moved); // 调整堆结构}return true;
    }
    

remove(Object o) 方法分为两种情况:

  1. 删除的是最后一个元素,直接删除即可,不需要调整。
  2. 删除的不是最后一个元素,从删除点开始以最后一个元素为参照调用 siftDown() 方法进行调整。

6.5 小结

PriorityQueue 提供了多种方法来插入、获取和删除元素,并自动维护堆的性质。add()offer() 用于插入元素,element()peek() 用于获取但不删除队首元素,remove()poll() 用于获取并删除队首元素,remove(Object o) 用于删除指定元素。这些方法在操作失败时的处理方式有所不同,但核心逻辑都是通过 siftUp()siftDown() 方法来维护堆的性质。

7 总结

PriorityQueue 是一个非常常用的数据结构,适用于需要按照优先级顺序处理元素的场景。它的底层实现是一个数组,通过堆的性质来维护元素的顺序。取出元素时按照优先级顺序(从小到大或者从大到小)进行取出。如果需要指定排序,元素必须实现 Comparable 接口或者传入一个 Comparator 来进行比较。

8 思维导图

在这里插入图片描述

9 参考链接

10 张手绘图详解Java 优先级队列PriorityQueue

关键字:临清建网站_东莞seo优化推广_湖南seo博客seo交流_网络推广推广培训

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: