简单介绍
堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
- 堆中某个结点的值总是不大于或不小于其父结点的值;
- 堆总是一棵完全二叉树。
将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
堆是非线性数据结构,相当于一维数组,有两个直接后继。
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(
k
i
≤
k
2
i
且
k
i
≤
k
2
i
+
1
)
或
(
k
i
≤
k
2
i
且
k
i
≤
k
2
i
+
1
)
(k_i \leq k_{2i} 且 k_i \leq k_{2i + 1}) 或 (k_i \leq k_{2i} 且 k_i \leq k_{2i + 1})
(ki≤k2i且ki≤k2i+1)或(ki≤k2i且ki≤k2i+1)
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
以上摘自百度百科。
具体实现
下面给出小根堆的两种实现:
循环实现:
//省略头文件
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define fa(x) (x>>1)
class Heap
{
public:
int a[(unsigned int)1e6 + 5], size;
void insert(int num) {//num x size 分别是欲插入的数、位置、堆长度
int x = ++size;
while (a[fa(x)] > num && fa(x) >= 1) {//不断的和自己的父亲比较
a[x] = a[fa(x)];//父亲赋值回孩子
x = fa(x);//不要忘了更新 x 的值
}
a[x] = num;
//show(size);
return;
}
void pop() {//弹出最小的数
if (size <= 0)return;//若堆以经没有值了就跳出函数
size--;//堆长先减一
int x = ls(1);
while (x <= size) {
if (x + 1 <= size && a[x + 1] < a[x])x++;//若右孩子在堆内且小于左孩子,则用右孩子
if (a[x] < a[size + 1])a[fa(x)] = a[x], x = ls(x);
else break;
}
a[fa(x)] = a[size + 1];//最后赋值
return;
}
void show(int x) {
printf("堆长 %d\n", size);
int cnt = 0, p = 0;
for (int i = 1, j = 0; i <= size; i +=j) {
p++;
for (j = 0; j < std::pow(2, p - 1) && i + j <= size; j++) {
printf("%d ", a[++cnt]);
}
putchar('\n');
}
return;
}
Heap() {
memset(a, 0, sizeof a);
size = 0;
};
private:
}heap1;
//省略主函数
递归实现:
//(*╹▽╹*)头文件再见~~
#define fa(x) (x>>1)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
int heap[(unsigned int)1e7], hsize;
inline void heap_insert(int x, int num) {
heap[x] = num;
if (heap[fa(x)] > num && fa(x) >= 1) {
heap[x] = heap[fa(x)];
heap_insert(fa(x), num);
}
return;
}
inline void h_pop(int x, int num) {
heap[x] = num;
if (ls(x) <= hsize && num > heap[ls(x)] && heap[ls(x)] <= heap[rs(x)]) {
heap[x] = heap[ls(x)];
h_pop(ls(x), num);
}
else if (rs(x) <= hsize && num > heap[rs(x)] && heap[ls(x)] >= heap[rs(x)]) {
heap[x] = heap[rs(x)];
h_pop(rs(x), num);
}
return;
}
//省略主函数
小根堆的两种实现就是这样啦~
大根堆把里面的符号换一下就可以了,拜拜~