C++ Heap 堆
STL 堆操作
初始化堆
vector<int>vectorArr = {3,4,5,6,7,1,2}; // 数组 make_heap(vectorArr.begin(), vectorArr.end(), less<int>()); // 创建最大堆 // make_heap(vectorArr.begin(), vectorArr.end(), greater<int>()); // 创建最小堆
判断堆
is_heap(vectorArr.begin(), vectorArr.end()); // 布尔值
插入元素
// 先调用 push_back先元素插入vector vectorArr.push_back(100); // 插入到最后 // 再调用 push_heap调整堆 push_heap(vectorArr.begin(), vectorArr.end());
弹出元素
// 先调用pop_heap将堆顶元素放到末尾 push_heap(vectorArr.begin(), vectorArr.end()); // 再调用pop_back再末尾元素弹出 vectorArr.pop_back();
堆排序
// 堆排序后不是一个真正的堆了,只是完成了排序。 // 堆排序算法。执行此操作之后,容器vector中的元素按照从小到大的顺序排列。 sort_heap(vectorArr.begin(), vectorArr.end()); // 排序之后可以用pop_heap() + pop_back()按顺序取出
二叉堆的定义
二叉堆是一种完全二叉树.
堆分为大顶堆和小顶堆
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。
当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
二叉堆满足的性质:
- 父节点的键值总是大于或等于(小于或等于) 任何一个子节点的键值.
- 每个节点的左子树和右子树都是一个二叉堆.
堆的存储
可以用数组来存储所有的节点.
在具体实现过程中,要注意数组[0]位置是否使用.
若
索引0
使用,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。
堆的操作
无论进行哪些操作.. 都必须保持两个性质!
- 堆是完全二叉树.
- 最大/最小堆性质
插入
- 每次插入都是将新数据放在数组最后。 这样保证了是完全二叉树.
- 然后再将这个元素插入到合适位置!
排入排序
删除
- 堆的删除操作只能删除堆顶元素.
- 为了便于重建堆. 实际操作是将最后一个元素赋值给栈顶元素.然后再将这个元素从栈顶从上向下调整.
- 对于最小堆来说: 若这个元素比左右孩子都小. 那么无需操作了. 否则. 将左右孩子中较小的元素提取上去. 该元素下降.
堆化数组
- 将一个数组看做是一个叶子节点已经堆化完成的堆.
- 对最后一个叶子节点的父亲节点到索引0位置的元素进行堆化(向下调整)
堆排序
- 每次取出堆顶元素. 即是排序结果.
- 由于堆也是用数组模拟的,故堆化数组后,第一次将A[0]与A[n - 1]交换,再对A[0…n-2]重新恢复堆。第二次将A[0]与A[n – 2]交换,再对A[0…n - 3]重新恢复堆,重复这样的操作直到A[0]与A[1]交换。由于每次都是将最小的数据并入到后面的有序区间,故操作完成后整个数组就有序了
实现自己的一个最小堆
#pragma once
#include "myinclude.h"
class MinHeap {
private:
vector<int> vec;
int cnt; // 个数
static const int StartIndex = 1;// 从1开始计数
public:
MinHeap() {
vec.clear();
vec.push_back(0); //
}
MinHeap(vector<int> data) {
vec.clear();
vec.push_back(0); //
int sz = data.size();
for (int i = 0; i < data.size(); ++i) {
vec.push_back(data[i]);
}
cnt = data.size();
MinHeapMakeHeap();
}
// 插入元素
void MinHeapInsert(int data){
vec.push_back(data);
cnt++;
shiftUp(cnt);
}
// 上溯
void shiftUp(int child) {
int tmp = vec[child];
int parent = child / 2;
while (parent >= StartIndex && child != StartIndex) {
if (vec[parent] <= tmp)
break;
//
vec[child] = vec[parent];
child = parent;
parent = child / 2;
}
vec[child] = tmp;
}
// 删除元素
void MinHeapPop() {
// int res = vec[StartIndex]; 若要返回就把这个元素返回
vec[StartIndex] = vec[cnt];
cnt--;
shiftDown(StartIndex);
}
// 向下调整
void shiftDown(int Index) {
int parent = Index;
int tmp = vec[parent];
int leftChild = parent * 2;
while (leftChild <= cnt) {
// 找到左右孩子中最小的数
if (leftChild + 1 <= cnt&&vec[leftChild + 1] < vec[leftChild]) {
leftChild++;
}
if (vec[leftChild] >= tmp) {
break;
}
vec[parent] = vec[leftChild];
parent = leftChild;
leftChild = parent * 2;
}
vec[parent] = tmp;
}
// 堆化数组
void MinHeapMakeHeap() {
int n = cnt;
for (int i = n / 2; i >= StartIndex; i--) {
shiftDown(i);
}
}
// 堆排序
void MinHeapSort() {
//
}
// 打印
void MinHeapPrint() {
for (int i = StartIndex; i <= cnt; i++) {
cout << vec[i] << ends;
}
cout << endl;
}
};