heap¶
1. min heap¶
- min heap 是一个完全二叉树并且是一个min tree.
min tree : 每个父亲节点都比孩子节点小
- min heap 可以用来快速找到最小元素
- 时间复杂度O(1) 以下介绍min heap的各种操作,maxheap同理可得
基本操作¶
1.1 数组模拟min heap¶
- 设置array[0]为空头节点
\[ parent[index]=\left\{
\begin{array}{rcl}
i/2 & {i>1}\\
1 &{i=1}\\
\end{array} \right. \]
\[ leftchild[index]=\left\{
\begin{array}{rcl}
2*i & {i*2<=n}\\
None &{i*2>n}\\
\end{array} \right. \]
\[ rightchild[index]=\left\{
\begin{array}{rcl}
2*i+1 & {i*2+1<=n}\\
None &{i*2+1>n}\\
\end{array} \right. \]
1.2 定义结构(对完全二叉树用数组表示):¶
1.3 初始化¶
heap* creat_heap(int maxsize){
heap* head=(heap*)malloc(sizeof(heap));
head->array=(int *)malloc(sizeof(int)*(maxsize+1));
head->capacity=maxsize;
head->size=0;
//把空节点的元素设置为该类型数据的最小元素,以确保任何一个根元素都比其大,如设置为负无穷
head->array[0]=mindata;
return head;
}
1.4 insertion¶
该操作以及接下来的操作的共同思想是:完全二叉树的结构是固定的,将要插入或删除的元素放入固定的位置,再比较调整元素间的位置即可 - 常规思路是用交换:
void insert{heap* head,int x}{
if(array is full) return;
head->array[++head->size]=x;
for(int i=size;head->array[i]<head->array[i/2];i/=2){
swap(head->array[i],head->array[i/2]);
}
}
void insert{heap* head,int x}{
if(array is full) return;
int i;
for(i=++head->size;head->array[i/2]>x;i/=2){
head->array[i]=head->array[i/2];
}
head->array[i]=x;
}
1.5 deletemin¶
- 删除最小元素,即根元素。核心在于要保持树的结构不变,即把最后一个元素先放到根节点上来,再调整各元素的位置
- 参照上文的插入思想,我们仍是先把其拿在手上作比较,找到合适的位置再插入
void deletemin(heap* head){ if(size==0) return; int lastelement=head->array[head->size--]; int i,child; for(i=1;i*2<=head->size;i=child){ child=2*i; //找到左右孩子中较小的一个 if(child<size&&head->array[child]>head->array[child+1]){ child++; } if(head->array[child]<lastelement){ head->array[i]=head->array[child]; }else{ break; } } head->array[i]=lastelement; }
1.6 buildheap¶
- 先直接读到数组里
- 从最后的非叶子节点开始调顺序(下沉操作),遍历到1位置
- 时间复杂度为O(n)
- 最差情况是所有元素都要下称且下称到底,即所有节点高度的和
- 完美二叉树有\(2^{h+1}-1\)个节点,所有节点的高度和为\(2^{h+1}-1-(h+1)\),其中高度h=logn,故时间复杂度为O(n)
- 与元素数据大小的先后无关
1.7 其他¶
- 找第k大的元素:建堆,然后做k次deletemin
- 删除堆中某节点: 先对其做上浮操作,再deletemin