(写给未来遗忘的自己)
大顶堆和小顶堆是两种二叉堆的类型。主要在优先队列、排序、动态数据流场景。
大顶堆:
大顶堆是每一个节点的值都大于或等于其子节点的值,因此堆顶元素是堆中最大的元素。常用于寻找最大值的场景。
#include<iostream>
#include <queue>
int main() {
// priority_queue 默认的是大顶堆
std::priority_queue<int>maxheap;
//加入元素
maxheap.push(10);
maxheap.push(12);
//堆顶元素
maxheap.top();
//弹出堆顶元素
maxheap.pop();
}
小顶堆:
小顶堆的每一个节点的值都小于等于其节点的值,因此堆顶元素是队中最小的元素。
#include<iostream>
#include <queue>
#include<vector>
int main() {
/*priority_queue 默认的是大顶堆
1. std::priority_queue: 这是C++标准库中提供的一个容器适配器,用于实现优先队列,底层通常使用堆(默认情况下是大顶堆)
2. int: 这是优先队列中存储的数据类型。在这个例子中,优先队列存储的是整数。
3.std::vector<int>: 这是底层存储的容器类型。std::priority_queue允许指定底层容器,默认是std::vector。这里显式指定了std::vector<int>作为存储容器。
4.std::greater<int>: 这是比较函数(或谓词),用于定义优先队列中的元素顺序。std::greater<int>表示当元素a比元素b“大”时,a应排在b之前。
由于priority_queue默认是大顶堆,所以使用std::greater<int>将其转变为小顶堆。
*/
std::priority_queue<int, std::vector<int>, std::greater<int>>minheap;
//加入元素
minheap.push(10);
minheap.push(12);
//堆顶元素
minheap.top();
//弹出堆顶元素
minheap.pop();
return 0;
}
自定义结构的堆:
#include<iostream>
#include <queue>
#include<vector>
struct Node
{
int id;
int priority;
//构造函数 用于创建 Node 对象时初始化 Node 结构体的成员变量。
Node(int id, int priority) : id(id), priority(priority){ }
};
//自定义比较器,小顶堆优先处理优先级最小的
struct compare {
//operator() 函数调用操作符重载,允许你把一个对象像函数一样使用。当调用compare的时候,会执行operator()定义的逻辑。
bool operator()(Node const& a, Node const& b) {
return a.priority > b.priority;
}
};
int main() {
std::priority_queue<Node, std::vector<Node>, compare> customminheap;
// 使用 emplace 直接传递构造函数参数,在堆中原地构造 Node 对象
customminheap.emplace(1, 5); // 构造 Node(1, 5)
customminheap.emplace(2, 4);
customminheap.top().id;
customminheap.pop();
return 0;
}
4.C++提供的一些算法处理堆
C++标准库还提供了一些算法来处理堆。make_heap
、push_heap
、pop_heap
这些函数可以用于将普通的数组或容器视作堆进行操作。
#include<iostream>
#include <queue>
#include<vector>
int main() {
std::vector<int>data = { 1,2,3,1,1,33,1,23,1 };
std::make_heap(data.begin(), data.end()); // 构建大顶堆
std::cout << "堆顶元素: " << data.front() << std::endl;
data.push_back(3);
std::push_heap(data.begin(), data.end()); // 插入新元素并调整堆
//作用:std::pop_heap 并不会直接删除堆顶元素,而是将堆顶元素与堆的最后一个元素交换,并对前 n - 1 个元素重新构建堆(假设堆的大小为 n)
//堆的最后一个元素现在是原来的堆顶元素,但堆的其他部分仍然是有效的堆结构。
std::pop_heap(data.begin(), data.end()); // 弹出堆顶元素
// data.pop_back() 删除 std::vector 容器的最后一个元素。由于 std::pop_heap 已将堆顶元素移至容器末尾,所以调用 pop_back() 就删除了这个堆顶元素。
data.pop_back();
}