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