数据结构第27节 优先队列

优先队列(Priority Queue)是在计算机科学中一种非常有用的抽象数据类型,它与标准队列的主要区别在于元素的出队顺序不是先进先出(FIFO),而是基于每个元素的优先级。具有较高优先级的元素会比低优先级的元素更早出队。在Java中,PriorityQueue类是实现优先队列的一种方式。

Java中的PriorityQueue

java.util.PriorityQueue是Java集合框架的一部分,它实现了Queue接口。PriorityQueue底层使用了一个名为堆的数据结构,通常是一个二叉堆,以保证每次操作的时间复杂度为O(log n),其中n是队列中的元素数量。

主要特点:
  1. 元素排序PriorityQueue默认按照自然排序(自然顺序)来排序元素,即元素必须实现Comparable接口,或者在创建PriorityQueue时提供一个Comparator对象来定制排序规则。

  2. 最小堆行为PriorityQueue默认表现得像一个最小堆,即队列的头部元素是最小的元素。如果需要最大堆的行为,可以通过自定义比较器来实现。

  3. 不允许null元素PriorityQueue不允许插入null元素。

  4. 不支持随机访问PriorityQueue不支持快速随机访问元素,因为它不是基于索引的结构。

常用方法:
  • add(E e):将指定的元素添加到此队列中。
  • offer(E e):如果可能立即添加指定的元素而不会违反队列的容量限制,则添加;否则返回false。
  • remove():检索并移除此队列的头;如果此队列为空,则抛出NoSuchElementException异常。
  • poll():检索并移除此队列的头;如果此队列为空,则返回null。
  • peek():检索但不移除此队列的头;如果此队列为空,则返回null。
  • size():返回队列中的元素个数。
  • isEmpty():如果队列中没有元素,则返回true。
示例代码:

下面是一个使用PriorityQueue的例子,展示如何创建和使用一个优先队列:

import java.util.PriorityQueue;
import java.util.Comparator;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 创建一个基于数字大小的优先队列
        PriorityQueue<Integer> pq = new PriorityQueue<>();

        // 添加元素
        pq.add(5);
        pq.add(1);
        pq.add(3);

        // 输出队列头部的元素
        System.out.println("Head element: " + pq.peek()); // 输出最小的元素,这里是1

        // 移除并输出队列头部的元素
        System.out.println("Removed head element: " + pq.remove()); // 输出并移除最小的元素,这里是1

        // 使用自定义比较器创建优先队列
        PriorityQueue<String> pqStrings = new PriorityQueue<>(new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return s2.compareTo(s1); // 反转字符串的排序顺序
            }
        });

        // 添加字符串元素
        pqStrings.add("Apple");
        pqStrings.add("Banana");
        pqStrings.add("Cherry");

        // 输出队列头部的元素
        System.out.println("Head element: " + pqStrings.peek()); // 输出最大的元素,这里是"Cherry"
    }
}

在这个例子中,我们创建了两个PriorityQueue实例。第一个实例是基于整数的优先队列,按照数字大小排序。第二个实例是基于字符串的优先队列,使用自定义的比较器来反转字符串的自然排序顺序。

优先队列在很多场景下都非常有用,比如任务调度、事件驱动模拟、Dijkstra算法中的最短路径计算、以及各种基于优先级的系统中。

下面我会给出几个具体的场景以及相应的Java代码实现,以便你了解优先队列在实际编程中的应用方式。

场景1:任务调度

在任务调度场景中,优先级高的任务会被优先执行。这里我们使用PriorityQueue来管理任务列表。

import java.util.PriorityQueue;

class Task implements Comparable<Task> {
    private String name;
    private int priority;

    public Task(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }

    public String getName() {
        return name;
    }

    public int getPriority() {
        return priority;
    }

    @Override
    public int compareTo(Task other) {
        return Integer.compare(this.priority, other.priority);
    }
}

public class TaskScheduler {
    private PriorityQueue<Task> tasks = new PriorityQueue<>();

    public void addTask(Task task) {
        tasks.add(task);
    }

    public Task getNextTask() {
        return tasks.poll();
    }

    public static void main(String[] args) {
        TaskScheduler scheduler = new TaskScheduler();
        scheduler.addTask(new Task("Task1", 3));
        scheduler.addTask(new Task("Task2", 1));
        scheduler.addTask(new Task("Task3", 2));

        while (!scheduler.tasks.isEmpty()) {
            Task task = scheduler.getNextTask();
            System.out.println("Executing: " + task.getName());
        }
    }
}

场景2:Dijkstra算法

Dijkstra算法用于在加权图中寻找两个顶点之间的最短路径。优先队列在这里用来保存待访问的顶点,按照它们的当前最小距离排序。

import java.util.*;

public class DijkstraAlgorithm {
    private Map<String, List<Edge>> graph = new HashMap<>();
    private Map<String, Integer> distances = new HashMap<>();
    private PriorityQueue<Edge> queue = new PriorityQueue<>();

    public void addEdge(String source, String destination, int weight) {
        graph.computeIfAbsent(source, k -> new ArrayList<>()).add(new Edge(destination, weight));
    }

    public void calculateShortestPaths(String startVertex) {
        distances.put(startVertex, 0);
        queue.add(new Edge(startVertex, 0));

        while (!queue.isEmpty()) {
            Edge edge = queue.poll();
            String vertex = edge.getDestination();
            if (distances.containsKey(vertex)) continue; // Already processed

            distances.put(vertex, edge.getWeight());
            for (Edge neighbor : graph.getOrDefault(vertex, Collections.emptyList())) {
                queue.add(new Edge(neighbor.getDestination(), distances.get(vertex) + neighbor.getWeight()));
            }
        }
    }

    public static void main(String[] args) {
        DijkstraAlgorithm dijkstra = new DijkstraAlgorithm();
        dijkstra.addEdge("A", "B", 5);
        dijkstra.addEdge("A", "C", 10);
        dijkstra.addEdge("B", "D", 3);
        dijkstra.addEdge("C", "D", 1);
        dijkstra.addEdge("C", "E", 2);
        dijkstra.addEdge("D", "E", 1);
        dijkstra.addEdge("D", "F", 5);
        dijkstra.addEdge("E", "F", 5);

        dijkstra.calculateShortestPaths("A");
        System.out.println(dijkstra.distances);
    }

    static class Edge implements Comparable<Edge> {
        private String destination;
        private int weight;

        public Edge(String destination, int weight) {
            this.destination = destination;
            this.weight = weight;
        }

        public String getDestination() {
            return destination;
        }

        public int getWeight() {
            return weight;
        }

        @Override
        public int compareTo(Edge other) {
            return Integer.compare(this.weight, other.weight);
        }
    }
}

场景3:事件驱动的模拟

在事件驱动的模拟中,事件按照发生的时间排序。优先队列可以用来保持事件列表的有序性。

import java.util.PriorityQueue;

class Event implements Comparable<Event> {
    private long time;
    private String description;

    public Event(long time, String description) {
        this.time = time;
        this.description = description;
    }

    public long getTime() {
        return time;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public int compareTo(Event other) {
        return Long.compare(this.time, other.time);
    }
}

public class EventDrivenSimulation {
    private PriorityQueue<Event> events = new PriorityQueue<>();

    public void scheduleEvent(long time, String description) {
        events.add(new Event(time, description));
    }

    public void runSimulation() {
        while (!events.isEmpty()) {
            Event event = events.poll();
            System.out.println("Time: " + event.getTime() + ", Event: " + event.getDescription());
        }
    }

    public static void main(String[] args) {
        EventDrivenSimulation simulation = new EventDrivenSimulation();
        simulation.scheduleEvent(1000, "Start");
        simulation.scheduleEvent(1010, "Event 1");
        simulation.scheduleEvent(1005, "Event 2");
        simulation.runSimulation();
    }
}

在上述代码中,我们创建了三个不同的场景,每个场景都展示了PriorityQueue在不同应用场景下的使用方式。希望这些示例能够帮助你更好地理解优先队列在实际编程中的作用。

相关推荐

  1. 数据结构27 优先队列

    2024-07-15 06:36:04       21 阅读
  2. 数据结构25 深度优先搜索

    2024-07-15 06:36:04       16 阅读
  3. 数据结构26 广度优先搜索

    2024-07-15 06:36:04       18 阅读
  4. 数据结构07队列

    2024-07-15 06:36:04       26 阅读
  5. 数据结构20 快速排序以及优化

    2024-07-15 06:36:04       26 阅读
  6. 数据结构21 归并排序以及优化方案

    2024-07-15 06:36:04       21 阅读
  7. 数据结构22 堆排序优化

    2024-07-15 06:36:04       20 阅读
  8. 数据结构24 二分查找

    2024-07-15 06:36:04       19 阅读
  9. 数据结构28 字典树

    2024-07-15 06:36:04       20 阅读
  10. 数据结构优先级队列

    2024-07-15 06:36:04       50 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-15 06:36:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-15 06:36:04       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-15 06:36:04       58 阅读
  4. Python语言-面向对象

    2024-07-15 06:36:04       69 阅读

热门阅读

  1. 速盾:cdn技术是什么意思?

    2024-07-15 06:36:04       22 阅读
  2. 使用adb连接安卓手机

    2024-07-15 06:36:04       22 阅读
  3. Android人脸解锁源码解析

    2024-07-15 06:36:04       16 阅读
  4. 速盾:高防cdn和普通cdn的区别?

    2024-07-15 06:36:04       29 阅读
  5. Tick数据的清洗和1分钟K线合成

    2024-07-15 06:36:04       18 阅读
  6. App测试自动化工具UIAutomator2的使用

    2024-07-15 06:36:04       23 阅读
  7. React@16.x(57)Redux@4.x(6)- 实现 bindActionCreators

    2024-07-15 06:36:04       28 阅读
  8. PyTorch构建一个肺部CT图像分类模型来分辨肺癌

    2024-07-15 06:36:04       18 阅读
  9. Python学生信息管理系统的设计与实现

    2024-07-15 06:36:04       27 阅读
  10. SQL优化

    SQL优化

    2024-07-15 06:36:04      30 阅读
  11. RocketMQ

    RocketMQ

    2024-07-15 06:36:04      23 阅读
  12. SpringBoot实战:定时任务

    2024-07-15 06:36:04       20 阅读