1、基本原理。
堆排序是一种树形构造排序,是对直接选择排序的有效改进。
堆的定义:具有n个元素的序列(a[0],a[1],...,a[n-1]),当且仅当满足(a[i]>=a[2*i],a[i]>=a[2*i+1])或者(a[i]<=a[2*i],a[i]<=a[2*i+1])时称之为堆。由堆的定义可以很直观的看出,堆顶元素必定是最大(小)值,完全二叉树可以很直观的表示堆的结构。堆顶为根,其它为左子树、右子树。堆排序主要分为两个步骤进行。
step 1、从右至左,从下到上。从第一个非叶子的节点为根节点(假定有n个元素,则第一个非叶子节点的下标为n/2-1)开始构建堆,这样到一直到以第一个节点为根节点(编号为0)构建堆时,整个二叉树结构就是一个标准的堆结构。
step 2、经过第一步的调整,整个二叉树就是一个标准的堆结构,因此,根节点就是最大(小)的元素。将根节点与当前堆的最后一个元素交换并将当前堆的最后一个元素除外的元素重新建堆。如此重复n-1次,则堆排序完成。
2、实现
/**
* @brief HeapAdjust 在堆内对以下标i为根结点的堆进行调整
* 即原来除了下标为i的左右子树均为堆结构,调整完成后,以i为根结点的堆也是堆结构
* @param array 存储堆的数组的起始地址
* @param i 要调整的结点编号
* @param length 堆长度
*/
void HeapAdjust(int* array,int i,int length)
{
int tempData=array[i];
for(int index=2*i+1;index<length;index=2*index+1)
{
//右子树的值大,右子树结点的值向上移动
if(index<length-1&&array[index]<array[index+1])
{
index++;
}
if(array[index]>tempData)
{
array[i]=array[index];
i=index;
}
else
{
break;
}
}
array[i]=tempData;
}
/**
* @brief heapSort 对序列array[0]到array[length-1]内元素进行堆排序
* @param array
* @param length
*/
void heapSort(int* array,int length)
{
//1、第一步,建堆
for(int i=length/2-1;i>=0;i--)
HeapAdjust(array,i,length);
//2、第二步
for(int len=length-1;len>0;len--)
{
std::swap(array[0],array[len]);
HeapAdjust(array,0,len);
}
}
int main()
{
int a[10]={11,42,53,25,36,6,75,8,26,4};
std::cout<<"before sort:"<<std::endl;
for(int i=0;i<10;++i)
std::cout<<a[i]<<"\t";
std::cout<<std::endl;
heapSort(a,10);
std::cout<<"after sort:"<<std::endl;
for(int i=0;i<10;++i)
std::cout<<a[i]<<"\t";
std::cout<<std::endl;
return 0;
}
3、运行结果。