堆排序是一种树形选择的排序算法,在排序过程中将数组看作是一棵完全二叉树。但其实它是顺序存储的结构,这里我们实现的是大根堆的建堆算法。
堆排序:建大根堆-->输出堆顶元素(和堆底元素交换)-->整理将其重新整理成为堆
(1)大根堆(堆顶元素大于或等于其对应的子节点)
- L[i]>=L[2*i]
- L[i]>=L[2*i+1]
(2)小根堆(堆顶元素小于或等于其对应的子节点)
- L[i]<=L[2*i]
- L[i]<=L[2*i+1]
一、构建初始大根堆
构建大顶堆的过程就是一个反复筛选的过程,从第一个非叶子结点开始,调用调整筛选的算法,逐步向上进行调整,直至堆顶元素。
调整算法:使用a[0]来暂存需要调整的元素值,从该节点的左孩子节点出发,比较左孩子结点与右孩子结点的值大小,选出值较大的结点。若该节点小于父节点的值,则不用进行调整;若该节点大于父节点的值,则将其值赋值给父节点,调整结点的下标值。在这一过程中,由于交换后可能会破坏掉刚建好的子堆,因此,需要使用循环,依次检查其子堆是否还满足大顶堆。i=i*2
实现代码:
//堆排序
//建堆过程
#include<iostream>
using namespace std;
typedef int Elemtype;
void Build_Heap(Elemtype a[],int len);
void AdjustDown(Elemtype a[],int k,int len);
void Heap_Sort(Elemtype a[],int len);
void Build_Heap(Elemtype a[],int len){//建大顶堆过程,从第一个非叶节点开始,逐步进行向上的调整
int i;
for(i=len/2;i>0;i-- ){
AdjustDown(a,i,len);
}
}
void AdjustDown(Elemtype a[],int k,int len){
a[0]=a[k];//在数组中,我们使用a[0]来暂存需要调整的元素
int i;
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 Heap_Sort(Elemtype a[],int len)
{
Build_Heap(a,len);
for(int i=len;i>1;i--){//将堆顶与堆尾元素交换
swap(a[i],a[1]);
AdjustDown(a,1,i-1);//输出a[i],继续调整至大顶堆
}
}
int main(){
Elemtype a[8]={0,2,3,7,5,4,1,6};//注意在这里a[0]是暂存元素的,所以输入的时候存放一个0值
Heap_Sort(a,7);
for(int j=1;j<=7;j++){
cout<<a[j]<<" ";
}
cout<<endl;
system("pause");
return 0;
}
需要注意的是:这里我们使用了a[0]来暂存需要调整的元素,所以a[0]的值我们赋予其为0