1.算法原理
- 算法基于顺序存储的“完全二叉树”:结点i的左孩子是2i;右孩子是2i+1;父节点是i/2;编号小于n/2的结点都是分支结点。
- 大根堆(根>=左、右),小根堆(根<=左、右)
- 建堆:编号<=n/2的所有结点依次”下坠“调整(自底向上处理分支结点),调整规则:小元素逐层”下坠“(与关键字更大的孩子交换)。
- 排序:将栈顶元素加入有序子序列(栈顶元素与栈底元素交换),栈底元素换到栈顶后,需要进行”下坠“调整,恢复”大根堆“的特性;重复上述重复n-1趟。
2.具体代码
//第一部分:排序算法
//9-7 堆排序(以大根堆为例)
//2020.09.26
void BuildMaxHeap(int A[],int len)
{
int i;
for(i=len/2;i>0;i--)
HeadAdjust(A,i,len);
}
void HeadAdjust(int A[],int k,int len)
{
int i;
A[0]=A[k];//将需要下坠的值暂存在A[0]中
for(i=k*2;i<=len;i*=2)
{
if(i<len&&A[i+1]>A[i])//若分支结点包含左右孩子节点,且右孩子大于左孩子
i++;
if(A[i]<A[0]) break;//若分支结点比孩子结点都大,则该节点下坠结束
else {
A[k]=A[i];//把较大的孩子结点的值赋给分支结点
k=i;//继续循环,直到下坠结束
}
}
A[k]=A[0];//下坠结束条件:1.循环到了叶子结点;2.分支结点大于左右孩子结点
}
//基于大根堆进行排序
void Swap(int *x,int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
void HeapSort(int A[],int len)
{
int i;
BuildMaxHeap(A,len);//先建立大根堆
for(i=len;i>1;i--)//len-1趟的交换和建堆
{
Swap(&A[1],&A[i]);//栈顶元素和栈底元素交换
HeadAdjust(A,1,i-1);//把剩余的待排序元素整理成堆
}
}
//小根堆的插入操作
void InsertHeap(int A[],int len,int num)//num表示需要插入到小根堆的数值
{
int i,k=len+1;//将K值定义为需要判断的位置
A[0]=num;
A[k]=num;
for(i=k/2;i>0;i/=2)//插入的数值不断上浮,直到不能上浮为止
{
if(A[i]<A[0]) break;//分支结点小于孩子节点,插入操作结束
else {
A[i]=A[k];
k=i;
}
}
A[k]=A[0];
}
//小根堆的删除操作
void DeleteHeap(int A[],int len,int index)
{
A[index]=A[len];
HeadAdjust(int A[],int index,int len-1);
}
3.性能分析
空间复杂度:O(1)
时间复杂度:建堆:O(n),排序:O(nlog2n);总的时间复杂度:O(nlog2n);
稳定性:不稳定
基于大根堆的堆排序得到”递增序列“,基于小根堆的堆排序得到”递减序列“。
版权声明:本文为weixin_42534963原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。