思维导图:
堆的概念:
根>=左右孩子节点的顺序存储二叉树
i的范围为n/2取下界,即最后一个双亲节点
小根堆:
大根堆:
堆的初始化:
以大根堆为例:
代码实现:
void BuildMaxHeap(int a[],int len){
for(int i=len/2;i>0;i--) //从后往前调整所有非终端节点
AdjustDown(a,i,len);
}
//将以k为根的子树调整为大根堆
void AdjustDown(int a[],int k,int len){ //数组、当前调整节点、节点大小
a[0] = a[k]; //哨兵节点
for(int i=2*k;i<=len;i*=2){ //每次循环的下一个节点是此节点的左孩子节点
if(i<len && a[i]<a[i+1]) //判断i的合法性且左孩子节点的值小于右孩子,让i指向右孩子节点
i++;
if(a[0]>=a[i]) //判断右孩子和哨兵节点的大小,若哨兵节点大,说明双亲节点大于左右孩子节点,退出本次循环
break;
else{ //否则赋值并改变k的值继续向下调整
a[k] = a[i];
k = i;
}
}
a[k] = a[0]; //将哨兵节点赋值到最终调整到的节点
}
时间复杂度: O(n) 与树的高度h有关
堆排序的算法思想:
1、建立一个大根堆
2、将堆顶元素与待排序序列最后一个元素交换
3、将待排序序列再次调整为大根堆
堆排序代码实现:
void HeapSort(int a[],int len){
int temp;
BuildMaxHeap(a,len);
for(int i=len;i>1;i--){
temp = a[i];
a[i] = a[1];
a[1] = temp;
AdjustDown(a,1,i-1); //每输出一个元素,i就要减1
}
}
int main(){
int i;
int a[5] = {NULL,2,11,6,9};
HeapSort(a,4);
for(i=1;i<5;i++)
printf("%d\t",a[i]);
}
堆排序的插入:
代码实现:
void AdjustUp(int a[],int k){
a[0] = a[k];
int i = k/2;
while(i>0 && a[i] < a[0]){ //没有调整到根节点且双亲节点小于孩子节点时
a[k] = a[i];
k = i;
i = k/2; //将i赋值为双亲节点继续调整
}
a[k] = a[0]; //将孩子节点的值赋值给最终调整的节点
}
堆排序的删除:
被删除的元素用堆底元素代替,然后让该元素不断“下坠”,直到无法下坠为止
1、代替
2、下坠
堆排序的性能:
时间复杂度: O(nlog2n)
时间复杂度: O(1)
不稳定