优先队列的使用

1. C++实现优先队列

1.1 基本头文件和声明

arduino 复制代码
#include <queue> // 必须包含此头文件

std::priority_queue<int> pq; // 默认为最大堆

// 模板参数依次为: 元素类型, 底层容器类型 (默认为 vector), 比较函数类型
std::priority_queue<type, container_type, comparison_type>  //完整模板

主要成员函数:

  • push(const value&) : 将一个新元素插入队列,并自动调整内部堆结构以维持其性质。时间复杂度 O(log N)
  • pop() : 移除队列顶部的元素(最大堆中的最大值,最小堆中的最小值)。注意,它不返回任何值。时间复杂度 O(log N)
  • top() : 返回队列顶部的常量引用。这是优先级最高的元素。时间复杂度 O(1)
  • empty() : 如果队列为空,返回 true。时间复杂度 O(1)
  • size() : 返回队列中元素的数量。时间复杂度 O(1)

1.2 最大堆

c 复制代码
#include <iostream>
#include <queue>

int main() {
    std::priority_queue<int> max_pq;  //声明最大堆
    int nums[5] = {3, 1, 4, 9, 0};
    
    for (int i = 0; i < 5; i++) max_pq.push(nums[i]);  //将数据加入堆
    
    while (!max_pq.empty()) {
        std::cout << max_pq.top() << ' ';  //访问最大元素
        max_pq.pop();  //移除堆顶元素
        
    }
    // 输出: 9 4 3 1 0
    return 0;  
}

1.3 最小堆

c 复制代码
#include <iostream>
#include <queue>
#include <functional>  //包含 std::greater

int main() {
    // 模板参数依次为: 元素类型, 底层容器类型 (默认为 vector), 比较函数类型
    std::priority_queue<int, std::vector<int>, std::greater<int>> min_pq; 
    int nums[5] = {3, 1, 4, 9, 0};
    
    for (int i = 0; i < 5; i++) min_pq.push(nums[i]);  //将数据加入堆
    
    while (!min_pq.empty()) { 
        std::cout << min_pq.top() << " "; // 访问最小元素 
        min_pq.pop(); 
    }
    // 输出: 0 1 3 4 9
}

1.4 存储自定义类型

对于复杂的对象,需要自定义比较逻辑。以一个任务(Task)为例,我们希望优先级高的任务先被处理。

方法一: 函数指针

c 复制代码
#include <iostream> 
#include <queue> 
#include <vector> 
// 定义一个普通的比较函数 
bool minHeapCompare(int a, int b) { 
    return a > b; //  实现最小堆
}

int main() {
    // 使用函数指针时,需要在模板参数中指定函数指针的类型 bool(*)(int, int),并且在构造 priority_queue 对象时传递函数名 minHeapCompare
    std::priority_queue <int, std::vector<int>, bool(*)(int, int)> min_pq(minHeapCompare);
    int nums[5] = {3, 1, 4, 9, 0};
    
    for (int i = 0; i < 5; i++) min_pq.push(nums[i]);  //将数据加入堆
    
    while (!min_pq.empty()) { 
        std::cout << min_pq.top() << " "; // 访问最小元素 
        min_pq.pop(); 
    }
    // 输出: 0 1 3 4 9
    
    return 0;
}

方法二:自定义比较器(仿函数)

c 复制代码
#include <iostream> 
#include <queue> 
#include <string>
#include <vector>

struct Task {
    int priority;
    std::string name;
        Task(int p, const std::string& n) : priority(p), name(n) {}
};

//定义一个比较器
struct TaskComparator {
    // 如果我们希望优先级数字大的在前,就需要 t1.priority < t2.priority 时返回 true
    // 返回True即告诉堆需要进行上浮和下沉操作(简单说就是需要交换目前比较元素的位置
    bool operator()(const Task& t1, const Task& t2) const {
        return t1.priority < t2.priority;
    }
};

int main() {
    std::priority_queue<Task, std::vector<Task>, TaskComparator> task_pq;
    Task tasks[5] = {
        Task(3, "task1"),
        Task(1, "task2"),
        Task(4, "task3"),
        Task(9, "task4"),
        Task(0, "task5")
    }
    
    while (!task_pq.empty()) {
        Task t = task_pq.top();
        task_pq.pop();
        std::cout << "Priority: " << t.priority << ", Name: " << t.name << std::endl;
    }
    
    /* 输出:
        Priority: 9, Name: task4
        Priority: 4, Name: task3
        Priority: 3, Name: task1
        Priority: 1, Name: task2
        Priority: 0, Name: task5
    */
    
    return 0;
}

方法三:使用lambda表达式(C++11及以后)

虽然不能直接将 lambda 作为模板参数传递,但可以在创建 priority_queue 实例时传入一个 lambda 实例

c 复制代码
#include <iostream>
#include <vector>
#incldue <queue>
#incldue <functional>

int main() {
    auto cmp = [](int left, int right) { return  left > right; };  //创建最小堆
    // 使用 decltype 来推导 lambda 的类型
    std::priority_queue <int, std::vector<int> decltype(cmp)> min_pq(cmp);
    int nums[5] = {3, 1, 4, 9, 0};
    
    for (int i = 0; i < 5; i++) min_pq.push(nums[i]);  //将数据加入堆
    
    while (!min_pq.empty()) { 
        std::cout << min_pq.top() << " "; // 访问最小元素 
        min_pq.pop(); 
    }
    // 输出: 0 1 3 4 9
    return 0;
}

2. Python使用优先队列

2.1 最小堆

ini 复制代码
import heapq

data = [5, 1, 3, 9, 2]

heapq.heapify(data)
# 原地堆化,默认为最小堆

print(data[0])
# 输出: 1

heapq.heappop(data)
# 弹出最小值

print(data[0])
# 输出: 2

heapq.heappush(data, 0)
# 插入元素

print(data[0])
# 输出: 0

2.2 最大堆

ini 复制代码
import heapq

data = [5, 1, 3, 9, 2]

#由于heapq只支持最小堆,因此将数值取反存出,取出是再取反

heap = []
for x in data:
    heapq.heappush(heap, -x)

2.3 存储复杂对象

python 复制代码
import heapq

tasks = []
# 这里使用元组示范,元组比较是从左向右的,因此优先级放在元组左边

heapq.heappush(tasks, (3, "xyz"))
heapq.heappush(tasks, (1, "xx"))
heapq.heappush(tasks, (5, "aa"))
heapq.heappush(tasks, (1, "xy"))

while tasks:
    priority, name = heapq.heappop(tasks)
    print(f"优先级 {priority}: {name}")
# 输出顺序:
#优先级 1: xx (因为"xx" < "xy")
#优先级 1: xy
#优先级 3: xyz
#优先级 5: aa

2.4 线程安全

python 复制代码
from queue import PriorityQueue

pq = PriorityQueue()

pq.put((3, "xyz"))
pq.put((1, "xx"))
pq.put((5, "aa"))

while not pq.empty():
    priority, name = pq.get()
    print(f"优先级 {priority}: {name}")
# 输出顺序:
#优先级 1: xx
#优先级 3: xyz
#优先级 5: aa
相关推荐
JieE21217 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack201 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树1 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2122 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2122 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术2 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦2 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户497863050732 天前
(一)小红的数组操作
算法·编程语言
怕浪猫2 天前
Electron 系列文章封面图
算法·架构·前端框架