适合范围
适合关键字非常多的情况,数据越大它的优势明显。即在1亿个元素里面选择最大的或者最小的100个关键字。
小根堆
小根堆即结点小于其孩子结点,所以根节点就是最小的结点。
存储方式:
因为要随机访问其孩子结点,所以我们要用顺序存储。用数组存储。
结点与孩子结点关系:
非叶子结点的下标:
小根堆手绘实现:
从最下标最大的非叶子结点开始调整,即非叶子结点小于其孩子结点。每次调整都要向下再次调整,因为调整之后下面的子树可能不符合小根堆。
思路:
每次循环都很固定,左右孩子结点比较然后再与父结点比较比较,从最大的非叶子结点开始循环。
即
HeadAdjust函数的实现
这样就建立出了一个小根堆,可以确定堆顶元素最小。若想的得到降序可以与最后一个元素交换,然后最前n-1个在进行小根堆,直到交换完毕。
完整代码:
void HeadAdjust(int A[],int k,int len){
int i;
A[0] = A[k];
for(i=2*k;i<=len;i*=2){
if(i<len&&A[i]>A[i+1])
i++;
if(A[0]<=A[i]) break;
else{
A[k] = A[i];
k = i;
}
A[k] = A[0];
}
}
void BuildMinHeap(int A[],int len){
int i;
for(i=len/2;i>0;i--)
HeadAdjust(A,i,len);
}
void HeapSort(int A[],int len){
int i;
BuildMaxHeap(A,len);
for(i=len;i>1;i--){
Swap(&A[i],&A[1]);
HeadAdjust(A,1,i-1);
}
}
算法实践:
大根堆
和小根堆一样,只是父节点大于其孩子结点。
只需取较大的孩子结点,然后该结点与其父节点比较
void HeadAdjust(int A[],int k,int len){
int i;
A[0] = A[k];
for(i=2*k;i<=len;i*=2){
if(i<len&&A[i]<A[i+1])//这个更改一下
i++;
if(A[0]>=A[i]) break;//这个更改一下
else{
A[k] = A[i];
k = i;
}
A[k] = A[0];
}
}
void BuildMaxHeap(int A[],int len){
int i;
for(i=len/2;i>0;i--)
HeadAdjust(A,i,len);
}
void HeapSort(int A[],int len){
int i;
BuildMaxHeap(A,len);
for(i=len;i>1;i--){
Swap(&A[i],&A[1]);
HeadAdjust(A,1,i-1);
}
}