priority_queue(优先队列)
std::priority_queue
是 C++ 标准模板库 (STL) 中提供的优先队列容器。优先队列是一种特殊的队列数据结构,其中元素是按照优先级排序的,默认情况下优先队列是一个最大堆(即总是优先返回最大元素)。std::priority_queue
允许我们快速访问队列中优先级最高的元素。
1. 基本概念
std::priority_queue
是一种基于堆的数据结构,堆是一个完全二叉树,其中每个父节点的值都大于(或小于)其子节点的值。priority_queue
是最大堆,因此最大元素始终位于队列的顶部。
2. 优先队列的使用
std::priority_queue
是通过模板类定义的,模板参数包括:
- 类型:优先队列中元素的类型。
- 容器:用于存储元素的底层容器,默认为
std::vector
。 - 比较函数:用于定义元素优先级的比较方式,默认是
std::less<T>
,表示最大堆。std::priority_queue<T, Container, Compare>
T
:存储元素的类型。Container
:底层容器类型(通常为std::vector
,也可以是std::deque
等)。Compare
:比较方式,默认是std::less<T>
,用于创建最大堆。如果希望创建最小堆,可以使用std::greater<T>
。
3. 常用操作
- push():将元素插入到优先队列中。
- pop():移除优先队列中优先级最高的元素(但不返回它的值)。
- top():返回优先队列中优先级最高的元素。
- empty():检查优先队列是否为空。
- size():返回优先队列中元素的数量。
4. 示例代码
4.1 最大堆(默认行为)
默认情况下,std::priority_queue
是一个最大堆,这意味着top()
函数返回当前优先队列中最大的元素。
#include <iostream>
#include <queue>
int main()
{
// 默认是最大堆
std::priority_queue<int> pq;
pq.push(10);
pq.push(30);
pq.push(20);
pq.push(5);
std::cout << "Priority queue size: " << pq.size() << std::endl;
// 输出最大元素并移除它
while (!pq.empty())
{
std::cout << pq.top() << " "; // 输出优先级最高的元素
pq.pop(); // 移除优先级最高的元素
}
return 0;
}
输出:
Priority queue size: 4
30 20 10 5
4.2 最小堆
为了实现最小堆,需要使用std::greater<T>
作为比较函数。可以在声明std::priority_queue
时指定std::vector<int>
作为容器,并使用std::greater<int>
来表示最小堆。
#include <iostream>
#include <queue>
#include <vector>
int main()
{
// 最小堆
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
minHeap.push(10);
minHeap.push(30);
minHeap.push(20);
minHeap.push(5);
std::cout << "Priority queue size: " << minHeap.size() << std::endl;
// 输出最小元素并移除它
while (!minHeap.empty())
{
std::cout << minHeap.top() << " "; // 输出优先级最高的元素
minHeap.pop(); // 移除优先级最高的元素
}
return 0;
}
输出:
Priority queue size: 4
5 10 20 30
4.3 自定义对象的优先级队列
可以通过自定义比较函数来定义复杂类型的优先级队列。例如,假设我们有一个Person
类,我们希望基于年龄创建一个优先队列:
#include <iostream>
#include <queue>
#include <vector>
struct Person
{
std::string name;
int age;
Person(std::string name, int age) : name(name), age(age) {}
};
// 比较函数,按年龄升序排列
struct ComparePerson
{
bool operator()(const Person& p1, const Person& p2)
{
return p1.age > p2.age; // 年龄小的优先级高
}
};
int main()
{
// 使用自定义比较函数
std::priority_queue<Person, std::vector<Person>, ComparePerson> pq;
pq.push(Person("Alice", 30));
pq.push(Person("Bob", 25));
pq.push(Person("Charlie", 35));
// 输出优先级最高的元素(年龄最小的)
while (!pq.empty())
{
Person p = pq.top();
std::cout << p.name << " (" << p.age << ")" << std::endl;
pq.pop();
}
return 0;
}
输出:
Bob (25)
Alice (30)
Charlie (35)
4.4 与STL算法结合
std::priority_queue
可以与STL算法结合使用。例如,使用std::vector
初始化优先队列,并直接插入一批元素。
#include <iostream>
#include <queue>
#include <vector>
int main()
{
std::vector<int> vec = {10, 20, 30, 5};
// 使用已有的数据构建优先队列
std::priority_queue<int> pq(vec.begin(), vec.end());
// 输出优先级最高的元素
while (!pq.empty())
{
std::cout << pq.top() << " ";
pq.pop();
}
return 0;
}
输出:
30 20 10 5
5. 优先队列的复杂度
push()
操作的时间复杂度为 O(log n)。pop()
操作的时间复杂度为 O(log n)。top()
操作的时间复杂度为 O(1)。
由于priority_queue
是基于堆实现的,所以插入、删除的操作会重新调整堆结构,保持堆的有序性。