PriorityQueue初始化和方法

PriorityQueue概述

PriorityQueue` 是 Java 中的一个数据结构,它是一个优先队列实现,可以用来存储一组元素,并根据其优先级进行排序和检索。优先队列是一种特殊的队列,其中元素被赋予了优先级,高优先级的元素在队列中排在低优先级元素的前面。

以下是 PriorityQueue 的一些重要特性和用法:

  1. 基本特性

    • PriorityQueue 是一个基于堆(heap)数据结构实现的,通常是一个最小堆(Min Heap),也可以通过传递比较器来创建最大堆(Max Heap)。
    • 元素根据其优先级自动排序,高优先级的元素在队列前面。
  2. 元素插入

    • 使用 add()offer() 方法将元素插入队列中。
  3. 元素获取

    • 使用 peek() 方法可以获取队列中优先级最高的元素,但不删除它。
    • 使用 poll() 方法可以获取并移除队列中优先级最高的元素。
  4. 遍历元素

    • PriorityQueue 并没有提供迭代器来遍历元素,因为它并不保证元素的顺序。
  5. 自定义优先级

    • 可以通过为构造函数传递自定义的 Comparator 对象来定义元素的优先级比较规则。如果不提供比较器,元素必须实现 Comparable 接口来自然排序。
  6. 线程安全性

    • PriorityQueue 不是线程安全的,如果多个线程同时访问一个 PriorityQueue 实例,需要进行外部同步处理。
  7. 应用场景

    • PriorityQueue 常用于一些需要按优先级处理任务的场景,如任务调度器、最短路径算法(如Dijkstra算法)等。

以下是一个示例,演示了如何创建和使用 PriorityQueue

import java.util.PriorityQueue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 创建一个最小堆的PriorityQueue
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        
        // 插入元素
        minHeap.add(5);
        minHeap.add(2);
        minHeap.add(8);
        
        // 获取并移除最小元素
        int smallest = minHeap.poll(); // 结果:2
        System.out.println("Smallest element: " + smallest);
        
        // 获取但不移除最小元素
        int smallestPeek = minHeap.peek(); // 结果:5
        System.out.println("Smallest element (peek): " + smallestPeek);
    }
}

使用比较器构造最大堆

PriorityQueue<ListNode> q = new PriorityQueue<>(lists.length, (a, b) -> a.val - b.val);

这里使用<>来指定元素类型,确保a和b能够正确地识别为ListNode类型,从而访问val属性。
需要注意初始容量不能是0,加入的元素也不能是null

// 使用 Lambda 表达式创建最大堆比较器
Comparator maxHeapComparator = (a, b) -> b - a;
PriorityQueue maxHeap = new PriorityQueue<>(maxHeapComparator);
Comparator 是一个函数式接口,它只包含一个抽象方法 compare(T o1, T o2),这个方法接受两个参数并返回一个整数,用于比较这两个对象的大小。由于 Comparator 是函数式接口,因此可以使用 Lambda 表达式来创建它的实例。

在上述代码中,(a, b) -> b.val - a.val 是一个 Lambda 表达式,它实际上是一个匿名函数,等价于以下的 compare 方法:

int compare(ListNode a, ListNode b) {
    return b.val - a.val;
}

Lambda 表达式的左侧 (a, b) 是参数列表,右侧 b.val - a.val 是函数体,表示通过比较 b.vala.val 的差值来确定两个对象的顺序。这个差值为正时,表示 ba 大,为负时,表示 ab 大,为零时,表示它们相等。

因此,Lambda 表达式 (a, b) -> b.val - a.val 是创建了一个比较器,用于按照 ListNode 对象的 val 属性从大到小排序。这个比较器可以传递给 PriorityQueue,以确保最大的节点在堆的顶部。Lambda 表达式的简洁性使得它成为创建匿名函数对象的一种便捷方式。

扩容机制

在 PriorityQueue 中,动态扩容是在插入元素时进行的。以下是动态扩容的一般细节:

初始化:创建一个初始容量(默认是11)的数组,并将第一个元素插入其中。

插入元素:当插入一个新元素时,首先将其添加到数组的末尾。然后,它会根据堆的性质,比较新元素和其父节点的值。如果满足堆的性质,操作结束。如果不满足,就将新元素和父节点交换位置,然后继续比较新元素和新的父节点,直到满足堆的性质为止。

数组扩容:如果在插入元素时发现数组已满,就需要进行扩容。扩容通常会创建一个更大的新数组,然后将所有元素从旧数组复制到新数组中。

扩容策略:通常情况下,扩容的策略是将数组的容量翻倍,以减少频繁扩容的次数。这样可以保持在插入大量元素时的高效性能。

需要注意的是,虽然 PriorityQueue 具有动态扩容的机制,但扩容操作的代价相对较高,因为需要复制数组的所有元素。因此,在处理大量数据时,建议初始化 PriorityQueue 时指定一个足够大的初始容量,以减少扩容的次数,提高性能。

你可能感兴趣的:(Java,java,数据结构)