优先队列的使用

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
相关推荐
仰泳的熊猫3 小时前
题目2580:蓝桥杯2020年第十一届省赛真题-分类计数
数据结构·c++·算法·蓝桥杯
qyzm3 小时前
牛客周赛 Round 136
数据结构·python·算法
qq_334903153 小时前
C++与人工智能框架
开发语言·c++·算法
夕珩3 小时前
Java 排序算法详解:冒泡排序、选择排序、堆排序
java·算法·排序算法
Magic--3 小时前
从入门到精通:快速排序的核心原理、实现与优化
数据结构·算法·排序算法
weixin_649555673 小时前
C语言程序设计第四版(何钦铭、颜晖)第十章函数与程序结构之统计完全平方数
c语言·数据结构·算法
沈阳信息学奥赛培训3 小时前
深搜算法 6300:Grid Path Construction(2418)
算法
2401_891482173 小时前
C++中的状态模式
开发语言·c++·算法
Magic--3 小时前
选择排序:原理、实现与优化
数据结构·算法·排序算法