堆树的定义
- 父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
- 每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
堆的存储
-
堆排序,通过数组实现
-
一个点的左儿子等于其下标乘2,右儿子等于下标乘2加1(及a[i]的左儿子a[2i]右儿子a[2i+1])
C++代码实现大顶堆,注释已表明
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
//堆排序,通过数组实现
//一个点的左儿子等于其下标乘2,右儿子等于下标乘2加1
//及a[i]的左儿子a[2*i]右儿子a[2*i+1]
//以下为大顶堆的实现
struct heap{
int a[1000005];
int n; //堆中一共有多少元素
//添加元素进堆 O(logn)
void push(int key){
a[++n] = key;
insert(n);
}
//对第i个元素进行从下到上的修正
void insert(int i){
if(i == 1)
return;
if(a[i] > a[i/2]){
swap(a[i],a[i/2]);
insert(i/2);
}
return;
}
//获取对顶元素 O(1)
int top(){
return a[1];
}
//使堆顶元素出堆
void pop(){
swap(a[n],a[1]);
n--;
repair(1);
}
//对第i个元素进行从上到下的修正
void repair(int i){
//获取孩子结点中元素最大的下标
int maxIndex = 0;
if(2*i+1<=n)
maxIndex = a[2*i]>a[2*i+1]?2*i:2*i+1;
else if(2*i==n)
maxIndex = 2*i;
if(a[i]<a[maxIndex] && maxIndex!=0){
swap(a[i],a[maxIndex]);
repair(maxIndex);
}
}
};
heap h;
int main(){
int i,j,b;
int n,x;
cin>>n;
for(i=1;i<=n;i++){
scanf("%d",&x);
h.push(x);
}
for(i=n;i>=1;i--){
b = h.top();
printf("%d ",b);
h.pop();
}
}