本文参考于《啊哈!算法》,作者为纪磊。
最小(大)堆
众所周知 ,堆是一颗完全二叉树,而堆主要用于辅助程序进行排序等操作,一般不会独立作为考试内容。
著名应用就是优先队列了等时间复杂度为(nlogn) 的排序操作,而且是从输入后,就已经排完序。
话说我怎么就记不住(priority queue)呢?
首先建树函数creat();
从最后一个非叶节点的节点开始,依次向“上”进行向下调整。
因为完全二叉树的性质,所以从最后一个节点也就是下标为第n/2个节点开始向上搜索
代码:
void creat(){
for(int i=n/2;i>=1;i--){
siftdown(i); //开始调整
}
return;
}
然后就看是调整函数siftdown(i);
先是判断扫描到的节点有没有子节点(左),如果有(左)先设置一个标记,转而判断是否有右子节点,如果有,与左节点比大小(因为是排序算法嘛)。判断完成后,如果发现标记与原来的节点下标不同了,就代表着有子节点并且如果比原节点大,就交换位置且让当前的位置维护成当前的标记。
代码:
void siftdown(int i){
int t,f=0; //t就是那个标记
while(i*2<=n && f==0){
//f代表着是否有子节点 没有退出则说明此节点为叶节点
if(heap[i]>heap[2*i]){
//原节点与左子节点判断大小
t=i*2;
}else{
t=i;
}
if(i*2+1<=n){
//是否有右节点
if(heap[t]>heap[i*2+1]){
//这里的heap[t]是左节点和原节点的最小值
t=2*i+1;
}
}
if(t!=i){
//原节点有子节点且比他自身小
change(t,i); //转换函数,要自己写一个新式的函数
i=t; //维护
}else{
f=1; //此节点为叶节点 退出
}
}
return;
}
这段代码提到了change函数,所以change函数长这个样子: