大堆和小堆
在 C++ 中,大堆(max heap)
和小堆(min heap)
是两种不同类型的堆数据结构,它们的主要区别在于堆顶元素的值。
大堆(max heap)
:
大堆是一种特殊的完全二叉树,其中每个节点的值都大于或等于其子节点的值。大堆的根节点(堆顶)是整个堆中最大的元素。大堆的插入和删除操作都是 O(log n) 的时间复杂度。
小堆(min heap)
:
小堆也是一种特殊的完全二叉树,其中每个节点的值都小于或等于其子节点的值。小堆的根节点(堆顶)是整个堆中最小的元素。小堆的插入和删除操作也是 O(log n)
的时间复杂度。
总结:
大堆的根节点是整个堆中最大的元素。
小堆的根节点是整个堆中最小的元素。
priority_queue
在 C++ 中,priority_queue
是一个基于堆的数据结构,它提供了一个类似于堆的数据结构。priority_queue
的元素总是按照优先级排序,最高优先级的元素总是在队列的顶部。
priority_queue 默认是大堆根。
priority_queue 的默认比较函数是 std::less<T>
,它是一个二元谓词,用于比较两个元素的大小。
当使用 std::less<T>
作为比较函数时,priority_queue
是一个大堆,即堆顶元素是整个堆中最大的元素。这是因为 std::less<T>
的定义是 bool operator()(const T& x, const T& y) { return x < y; },
即如果 x 小于 y,则返回 true,否则返回 false。因此,priority_queue
的元素总是按照降序排列,堆顶元素是整个堆中最大的元素。
如果需要创建一个小堆,可以使用 std::greater<T>
作为比较函数。std::greater<T>
的定义是 bool operator()(const T& x, const T& y) { return x > y; }
,即如果 x 大于 y,则返回 true,否则返回 false。因此,使用 std::greater<T>
作为比较函数时,priority_queue
是一个小堆,即堆顶元素是整个堆中最小的元素。
在 C++中,可以使用 priority_queue
或 heap
来实现大堆和小堆。在构造 priority_queue
或 heap
时,需要指定比较函数来确定是大堆还是小堆。例如,使用 greater<T>
可以构造一个小堆,使用 less<T>
可以构造一个大堆(这里注意英文单词greater和less和大堆小堆的大小是相反的!less大堆根,greater小堆根)。
priority_queue
是 C++ 标准模板库(STL)中的一个容器适配器,它提供了一个类似于堆的数据结构。priority_queue
的元素总是按照优先级排序,最高优先级的元素总是在队列的顶部。priority_queue
提供了一些常用的方法,包括 top()
和 pop()
。
top() 方法:
top()
方法用于访问priority_queue
的顶部元素,即优先级最高的元素。如果 priority_queue
为空,则调用 top()
方法会抛出一个 std::out_of_range
异常。
pop() 方法:
pop()
方法用于删除 priority_queue
的顶部元素,即优先级最高的元素。如果 priority_queue
为空,则调用 pop()
方法会抛出一个std::out_of_range
异常。
总结:
top()
方法用于访问 priority_queue 的顶部元素。
pop()
方法用于删除 priority_queue 的顶部元素。
在实际使用中,top() 和 pop() 方法通常一起使用,用于访问和删除 priority_queue 的顶部元素。因为priority_queue 默认是大堆根,所以使用该特性可以拿到一个排序后的vector。例如,下面的代码创建了一个 priority_queue,并使用 top() 和 pop() 方法访问和删除元素,并得到一个元素从大到小排序的vector。
#include <queue>
#include <vector>
#include <iostream>
int main() {
std::priority_queue<int> pq;
std::vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
std::vector<int> res;
for (int num : nums) {
pq.push(num);
}
while (!pq.empty()) {
res.emplace_back(pq.top());
pq.pop();
}
for(int r: res){
std::cout << r << " ";
//9 6 5 5 5 4 3 3 2 1 1
}
return 0;
}