还是建议全屏阅读 O~
今天老师讲了一下堆,就在这里做一个小结吧~
堆,其实可以把它理解为一棵完全二叉树。我们所见到和用到的堆大多数都是二叉堆,所以这里直接把二叉堆称为堆。堆分为大根堆和小根堆。所谓大根堆 就是一颗完全二叉树,但是他的以每一个一节点作为根节点的子树中,根节点,也就是root是字数中最大的至(包括以整个完全二叉树和根节点)。而小根堆则反之。堆在我们的脑海之中是一棵完全二叉树,但是他实际是用一个数组来存储的,支持两种操作。我们一般把存储堆的数组命名为 Heap ,(老师说最好大写),支持的两种操作分别是:
- Put_Heap 用于在堆的末尾插入一个新的元素并且维护原本堆
- Get_Heap 删除根节点并且选举出新的根节点,即维护这个堆
同时,堆还有一个重要的性质:
那就是:
若我们设一个有儿子的一个节点在数组中的位置为 father, 那么他的两个儿子的位置分别为:
father * 2, father * 2 + 1
若不理解的可以自行在纸上画出一棵二叉树来研究。
下面是小根堆中两种操作的代码:
void Put_Heap(int x) {
//x为要插入的元素
Heap[++Heap_Size] = x;
int fa, now = Heap_Size;
while (now > 1) {
fa = now >> 1;
if (Heap[fa] <= Heap[now]) break;
swap(Heap[fa], Heap[now]);
now = fa;
}
}
int Get_Heap() {
int now, son, res;
res = Heap[1];
Heap[1] = Heap[Heap_Size--];
now = 1;
while (now * 2 <= Heap_Size) {
//没有越界
son = now * 2;//先暂定为和左儿子交换
if (son < Heap_Size && Heap[son + 1] < Heap[son]) {
//如果存在右儿子且右儿子小于左儿子
son++;//现在的下标就是右儿子的下标
}
if (Heap[now] <= Heap[son]) {
break;//已经满足小根堆,就直接跳出