【5. C++ 优先队列(priority_queue)深度解析】


引言:

优先队列(priority_queue)是一种带有优先级的队列,不同于普通的先进先出(FIFO)队列,它保证每次取出的元素都是当前优先级最高的元素。其底层实现通常是堆(Heap),因此插入和删除的时间复杂度都是O(logN),访问队首元素的时间复杂度是O(1)


1.1 适用场景

优先队列常用于:

  • 任务调度(如操作系统的进程调度)
  • 图算法(如 Dijkstra 最短路径、Prim 最小生成树)
  • 数据流处理(如动态求前 K 大/小的数)

1.2 基本用法

在 C++ 中使用优先队列,需要包含头文件 <queue>,并通过以下方式初始化:

#include <queue>

priority_queue<int> pq; // 默认是大根堆

2. priority_queue 的常用操作

方法作用时间复杂度
pq.top()访问队首(最大或最小)元素O(1)
pq.push(x)插入元素 xO(logN)
pq.pop()删除堆顶元素O(logN)
pq.size()获取队列中元素个数O(1)
pq.empty()判断队列是否为空O(1)

2.1 基本示例

#include <iostream>
#include <queue>

using namespace std;

int main() {
    priority_queue<int> pq;

    pq.push(5);
    pq.push(2);
    pq.push(8);
    pq.push(3);

    cout << "队首元素: " << pq.top() << endl;

    pq.pop(); // 移除最大元素

    cout << "移除后队首元素: " << pq.top() << endl;
    
    return 0;
}

输出:

队首元素: 8
移除后队首元素: 5

3. 设置优先级

3.1 priority_queue 默认规则

默认情况下,priority_queue 使用 大根堆(即堆顶是最大值):

priority_queue<int> pq; // 大根堆,每次取最大值

如果需要 小根堆(堆顶是最小值),可以使用 greater<int> 作为比较器:

priority_queue<int, vector<int>, greater<int>> pq; // 小根堆,每次取最小值

3.2 示例:小根堆 vs 大根堆

#include <iostream>
#include <queue>

using namespace std;

int main() {
    priority_queue<int> maxHeap; // 默认大根堆
    priority_queue<int, vector<int>, greater<int>> minHeap; // 小根堆

    int arr[] = {4, 1, 7, 3, 8};

    for (int num : arr) {
        maxHeap.push(num);
        minHeap.push(num);
    }

    cout << "大根堆队首: " << maxHeap.top() << endl;
    cout << "小根堆队首: " << minHeap.top() << endl;

    return 0;
}

输出:

大根堆队首: 8
小根堆队首: 1

4. 自定义排序规则

如果优先队列中存储的是结构体或需要使用特殊排序规则,可以使用 自定义比较函数

4.1 使用 struct 作为比较器

#include <iostream>
#include <queue>

using namespace std;

struct Compare {
    bool operator()(int a, int b) {
        return a % 10 > b % 10; // 依据个位数大小排序
    }
};

int main() {
    priority_queue<int, vector<int>, Compare> pq;

    pq.push(21);
    pq.push(34);
    pq.push(15);
    pq.push(42);

    while (!pq.empty()) {
        cout << pq.top() << " ";
        pq.pop();
    }

    return 0;
}

输出:

42 34 15 21

解析:这里我们自定义了按个位数排序的规则,堆顶始终是个位数最小的元素


4.2 结构体存入 priority_queue

priority_queue 需要存储结构体时,必须提供比较规则,否则编译会报错。

#include <iostream>
#include <queue>

using namespace std;

// 结构体
struct Point {
    int x, y;
    
    // 重载小于运算符,实现按 `x` 降序排列
    bool operator<(const Point& other) const {
        return x < other.x;
    }
};

int main() {
    priority_queue<Point> pq;

    pq.push({2, 5});
    pq.push({8, 3});
    pq.push({1, 9});

    while (!pq.empty()) {
        cout << "(" << pq.top().x << ", " << pq.top().y << ") ";
        pq.pop();
    }

    return 0;
}

输出:

(8, 3) (2, 5) (1, 9)

解析:这里 operator< 规定了 x 值越大,优先级越高,因此 8,3 先出队。


5. priority_queue vs sort

注意priority_queue 的比较规则和 sortcmp 函数刚好相反

bool cmp(int a, int b) {
    return a > b; // `sort()` 降序
}

struct Compare {
    bool operator()(int a, int b) {
        return a < b; // `priority_queue` 降序
    }
};

如果 sort(a, a+n, cmp) 使数组 从大到小排序,那么 priority_queue<int, vector<int>, Compare> 会创建一个 小根堆


6. 总结

6.1 priority_queue 核心知识点

  • 优先队列是一种特殊的队列,保证每次取出的元素是当前优先级最高的
  • 默认使用大根堆priority_queue<int>),小根堆需使用 greater<int>
  • 存储结构体时,需要重载 operator<提供自定义比较器

6.2 priority_queue vs sort

数据结构适用场景时间复杂度
priority_queue需要动态维护最大/最小值O(logN)
sort()需要对整个数据排序O(NlogN)

如果数据量较小,可以使用 sort() 直接排序;如果数据量很大且需要动态维护最大/最小值,则 priority_queue 是更好的选择。


6.3 priority_queue 适用场景

任务调度(优先级最高的任务先执行)
Dijkstra 最短路径(维护当前最短路径的节点)
求前 K 大/小的元素(流式数据处理)

希望这篇文章能帮助你掌握 priority_queue!🚀


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值