堆是什么呢?堆通常可以看成是一棵完全二叉树
那什么是完全二叉树呢?
若设二叉树的深度为h
除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数
第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
我们知道二叉树可以用数组模拟,堆自然也可以。现在让我们来画一棵完全二叉树:
我们很容易就可以看出一个结点的father的下标是当前结点u的下标 div 2
那么这样的一个东西有什么用呢?
我们需要让它维护一些信息,就像BST(二叉搜索树)一样{这个我们以后再讲}
现在给出堆得一些性质
-
堆中某个节点的值总是不大于或不小于其父节点的值;(1)
-
堆总是一棵完全二叉树。(2)
我们就很容易发现它的时间复杂度一般跟这堆的层数有关
又因为完全二叉树这个强力的形态支撑,会发现它的时间复杂度是O(logn)
堆还分为两种类型:大根堆和小根堆
顾名思义,就是保证是所结点的father的值比自己大/小(其实就是性质(1))
那么在堆的顶端就是我们整个堆中的最值了
对于这种数据结构我们又如何去维护呢?
下面给出几种操作
1.上浮
2.下降
3.插入
我们以大根堆为例,
首先我们要插入元素k的初始位置,然后再将它在这个堆中上浮同时维护堆的完全二叉树性质
下面是寻找初始位置的一段代码
procedure find(k:longint);
begin
inc(weight);//weight表示堆的大小
a[weight]:=k;
up(weight);//使新插入的元素k上升到它自己合适的位置
end;
接下来是上浮操作
procedure up(id:longint);
var t:longint;
begin
if id =1 then exit;//如果现在来到了堆顶,那么直接退出
if a[id]>a[id div 2] then //判断当前节点是否满足堆的性质
begin
t:=a[id]; a[id]:=a[id div 2]; a[id div 2]:=t;
end;
up(id div 2);//递归定义
end;
在维护了堆以后,我们要进行堆顶元素的弹出
function push:longint;
begin
push:=a[1];//取堆顶
a[1]:=a[weight];//将最后一个元素提到堆顶(这里维护了堆的完全二叉树性质)
a[weight]:=0;
dec(weight);
down(1);//维护最上方的元素将其下放
end;
接下来是下放操作
procedure down(id:longint);
begin
k:=max(a[id*2],a[id*2+1]);//取两者中的最大值
if a[id]>=k then exit;//此时满足堆的性质
if k=a[id*2] then
begin
t:=a[id]; a[id]:=a[id*2]; a[id*2]:=t;
down(id*2);
end
else begin t:=a[id]; a[id]:=a[id*2+1]; a[id*2+1]:=a[id]; down(id*2+1); end;
end;
最基础的堆本人就讲到这里了,还有很多数据结构等待大家学习。
(代码是手写的,如果有错误请见谅)
其实我是从csdn搬过来的O(∩_∩)O