C++ 入门19:STL 容器之优先队列(priority_queue)

往期回顾:

C++ 入门16:STL 容器之集合(set)与多重集合(multiset)_stl 集合-优快云博客

C++ 入门17:STL 容器之映射(map)与多重映射(multimap)_c++ 17 -优快云博客

C++ 入门18:STL 容器之栈(stack)与队列(queue)-优快云博客


 C++ 入门19:STL 容器之优先队列(priority_queue)

一、前言

今天我们将学习 C++ 标准模板库(STL)中的 priority_queue(优先队列)。优先队列是一种特殊的队列数据结构,它会根据元素的优先级来决定出队的顺序,而不是根据插入的顺序。通常用于需要频繁访问最大值或最小值的场景,比如任务调度、图算法等。

1. 什么是优先队列(priority_queue)?

优先队列是一种根据优先级来管理元素的队列。与普通队列不同,优先队列中插入的元素会根据优先级进行排序。C++ STL 中的 priority_queue 是基于堆(heap)实现的,通常是最大堆(Max Heap),即队头元素总是优先级最高的元素。

基本特性

  • 默认情况下,priority_queue 是最大堆,队头总是优先级最高的元素。
  • 你可以自定义优先级,例如构造最小堆(Min Heap)来让队头始终是优先级最低的元素。

2. 创建优先队列

引入头文件

在使用 priority_queue 之前,需要引入头文件 <queue>

#include <queue>

创建优先队列

创建一个 priority_queue 容器非常简单,它与普通队列(queue)的创建方法类似,只不过它的元素默认是按照优先级排序的。

示例代码:
#include <iostream>
#include <queue>
using namespace std;

int main() {
    // 创建一个整数类型的优先队列,默认是最大堆
    priority_queue<int> pq;

    // 向优先队列中插入元素
    pq.push(10);
    pq.push(20);
    pq.push(15);

    // 输出队头元素
    cout << "Top of priority_queue: " << pq.top() << endl;  // 输出 20

    return 0;
}

常用成员函数

  • push():向优先队列中插入元素。
  • pop():弹出队头元素(即优先级最高的元素)。
  • top():访问队头元素。
  • empty():检查优先队列是否为空。
  • size():返回优先队列中的元素个数。
示例代码:
priority_queue<int> pq;

pq.push(10);
pq.push(30);
pq.push(20);

cout << "Top element: " << pq.top() << endl; // 输出 30

pq.pop(); // 弹出 30

cout << "Top element after pop: " << pq.top() << endl; // 输出 20

cout << "Size of priority_queue: " << pq.size() << endl; // 输出 2

3. 自定义优先级(最小堆)

默认情况下,priority_queue 是一个最大堆,这意味着队头元素是优先级最高的元素。如果我们需要构建一个最小堆(即队头元素是优先级最低的元素),可以通过自定义比较器来实现。

自定义比较器

我们可以使用 std::greater<T> 来实现最小堆。std::greater<T> 是一个标准库提供的比较器,它会返回 true 如果第一个元素大于第二个元素。我们可以将它传递给 priority_queue 来实现最小堆。

示例代码:
#include <iostream>
#include <queue>
#include <functional> // 引入 std::greater
using namespace std;

int main() {
    // 创建一个最小堆(priority_queue 的比较器设置为 std::greater<int>)
    priority_queue<int, vector<int>, greater<int>> minHeap;

    minHeap.push(10);
    minHeap.push(30);
    minHeap.push(20);

    cout << "Top element of min heap: " << minHeap.top() << endl;  // 输出 10

    return 0;
}

自定义比较函数

除了使用标准库提供的比较器外,我们还可以自定义一个比较函数来实现更灵活的排序方式。自定义比较函数需要符合优先队列的要求:返回 true 时表示队头元素优先级高。

示例代码(自定义比较器):
#include <iostream>
#include <queue>
using namespace std;

// 自定义比较函数,用于创建最小堆
struct Compare {
    bool operator()(int a, int b) {
        return a > b;  // 返回 true 时表示 b 有更高的优先级
    }
};

int main() {
    // 使用自定义比较器创建一个最小堆
    priority_queue<int, vector<int>, Compare> minHeap;

    minHeap.push(10);
    minHeap.push(30);
    minHeap.push(20);

    cout << "Top element of min heap: " << minHeap.top() << endl;  // 输出 10

    return 0;
}

4. priority_queue 的应用

优先队列在很多实际场景中都有应用,以下是几个常见的应用场景。

任务调度

在操作系统中,优先队列可以用于任务调度。不同的任务有不同的优先级,系统会根据任务的优先级来决定任务的执行顺序。优先队列可以帮助我们高效地获取优先级最高的任务。

示例代码:
#include <iostream>
#include <queue>
using namespace std;

struct Task {
    int priority;
    string name;

    // 自定义比较器:优先级高的任务先处理
    bool operator<(const Task& other) const {
        return priority < other.priority;
    }
};

int main() {
    priority_queue<Task> taskQueue;

    taskQueue.push({3, "Task 1"});
    taskQueue.push({5, "Task 2"});
    taskQueue.push({1, "Task 3"});

    while (!taskQueue.empty()) {
        cout << "Processing " << taskQueue.top().name << " with priority " << taskQueue.top().priority << endl;
        taskQueue.pop();
    }

    return 0;
}

图算法中的优先队列

在图算法(如 Dijkstra 算法)中,优先队列常用于维护每个节点的最短路径值。通过优先队列,我们可以高效地从图的节点中选择下一个要处理的节点。

示例代码(Dijkstra 算法中优先队列的应用):
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

typedef pair<int, int> pii; // pair<权重, 节点编号>

void dijkstra(int start, vector<vector<pii>>& graph, int n) {
    vector<int> dist(n, INT_MAX); // 初始化距离为无穷大
    dist[start] = 0;

    priority_queue<pii, vector<pii>, greater<pii>> pq; // 最小堆,存储 {距离, 节点}
    pq.push({0, start}); // 起点的距离是 0

    while (!pq.empty()) {
        int u = pq.top().second; // 当前节点
        int d = pq.top().first;  // 当前节点的距离
        pq.pop();

        if (d > dist[u]) continue; // 如果当前距离大于已知最短距离,跳过

        for (auto& edge : graph[u]) {
            int v = edge.first;   // 邻接节点
            int weight = edge.second; // 边的权重

            if (dist[u] + weight < dist[v]) {
                dist[v] = dist[u] + weight;
                pq.push({dist[v], v});
            }
        }
    }

    // 输出最短距离
    for (int i = 0; i < n; ++i) {
        cout << "Distance from node " << start << " to node " << i << " is " << dist[i] << endl;
    }
}

int main() {
    int n = 5; // 节点数量
    vector<vector<pii>> graph(n);

    // 初始化图(邻接表)
    graph[0].push_back({1, 10});
    graph[0].push_back({4, 5});
    graph[1].push_back({2, 1});
    graph[1].push_back({4, 2});
    graph[2].push_back({3, 4});
    graph[3].push_back({0, 7});
    graph[3].push_back({2, 6});
    graph[4].push_back({1, 3});
    graph[4].push_back({2, 9});

    dijkstra(0, graph, n);  // 从节点 0 开始计算最短路径

    return 0;
}

结语

以上就是 C++ 标准模板库中的 priority_queue(优先队列)的基础知识点了。优先队列是一种根据元素优先级排序的特殊队列,广泛应用于需要频繁访问最大值或最小值的场景,例如任务调度、图算法等。我们了解了如何创建优先队列、如何自定义比较器来实现最大堆和最小堆,并通过实际示例演示了优先队列的应用。掌握了优先队列之后,可以在处理涉及优先级排序的问题时更加高效和便捷。基本上在开发中都会用到的,大家多看看,一定要掌握。

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值