堆排序详解
思想:堆排序是一种将a[1...n]看成一棵树,利用完全二叉树中双亲结点和孩子结点的关系,在当前无序区中选择关键字最大或者最小的元素。
堆排序分为:
大根堆:a[i]>=a[2*i]、a[i]>=[2*i+1]
小根堆:a[i]<=a[2*i]、a[i]<=a[2*i+1]
如下图:大根堆[20,17,8,1,16,3]、小根堆[3,7,8,17,16,28]
示例:53 17 78 9 45 65 87 32
1、建立大根堆:
①从最下面的第一个根结点开始,如下图i=4,将其和它的最大的子节点交换,因为9只有一个左结点23,直接交换
②i=3,78的两个结点中87最大,将78和87交换
③i=2,17的两个结点中45最大,将45和17交换
④i=1,53的两个节点中,87大于35,交换87和53,此时i=3,继续比较,53的两个结点78最大,将78与53交换。
最后得到大根堆为:
2、得到排序数组
①将根和最后一个结点交换,再将1~7调整为大根堆
②将根和该堆的最后一个节点交换(注意这里87已经不属于堆),即交换78和53,再进行①操作,直到最后得到排序数组
代码实现(c++)
#include <bits/stdc++.h>
using namespace std;
void buildHeap(int *a,int n,int i)
{
int temp;
while(2*i<n)
{
//取左右结点中值最大的结点和父节点比较
if(2*i+1<n&&2*i+2<n) temp=(a[2*i+1]>a[2*i+2])?(2*i+1):(2*i+2);
else if(2*i+1<n) temp=2*i+1;
else break;
if(a[temp]>a[i])
{
swap(a[i],a[temp]);
i=temp;//以该节点为父节点,建立大根堆
}
else break;
}
// for(int i=0;i<n;i++) cout<<a[i]<<' ';
// cout<<endl;
}
int main()
{
int n=8;
int a[n]={53,17,78,9,45,65,87,32};
while(n)
{
//创建大根堆
for(int i=n/2-1;i>=0;i--)
{
buildHeap(a,n,i);
}
for(auto i:a) cout<<i<<' ';
cout<<endl;
//每次将根和最后的结点交换
swap(a[0],a[n-1]);
//将剩下的数字创建大根堆
n--;
}
return 0;
}
输出为: