一.堆排序即其定义:
堆是一种特殊的完全二叉树,树的相关概念如果不清楚可以自行搜索,或者看我后续的博客,堆分两种,任意一根结点大于其左右子树的完全二叉树我们叫大根堆,任意一根结点大于其左右子树的完全二叉树则称为小根堆,由此我们知道,根节点一定是整棵树的最大/最小值,通过后续调整堆的结构,我们可以实现排序的效果,利用这种堆结构所作的排序我们称为堆排序
二.堆的结构
这里用数组实现类似堆的效果,给出数组int arr[]={0,49,38,65,97,76,13,27,49},由于堆的结点下标以1开始,所以这里添加多添加一个0号元素,给出还未调整的树的结构,如下图所示
三.堆如何调整
思路简单概述为:从根结点开始,根节点与左右子树较大者比较,若当前根j结点较大,说明已经找到待调整的位置,将根结点元素插入该位置即可,否则调整左右子树较大者的值到根结点,标记左右子树较大者的结点序号作为根结点序号,继续与左右子树进行上述比较,直至找到合适位置 。
四.堆排序
我们已经知道如何对堆调整,试想,初始状态一个大根堆n个元素,输出根结点的值,根结点与最后一个结点交换,排除一个结点,从根结点开始对剩余元素开始堆调整,输出根结点的值,重复上述步骤,得到的输出结果就是降序的,那问题是,如何初始化一个大根堆?
五.如何初始化堆
一颗含n个结点的完全二叉树,含子树的结点的最大结点序号是n/2,从n/2开始从后往前对根结点进行堆调整,就能得到一个大根堆
六.代码
#include <stdio.h>
//创建堆排序数组(0号元素是凑数的)
int arr[]={0,49,38,65,97,76,13,27,49};
int heap_size=sizeof(arr)/sizeof(int)-1;
//堆调整(大根堆)
void heap_Adjust(int arr[],int s,int m)
{
//待插入的结点
int sert_val=arr[s];
for(int j=s*2;j<=m;j*=2)
{
//判断当前结点左子树和右子树大小,计算较大者的下标
if(arr[j+1]>arr[j]&&j<m)
j++;
//找到插入位置
if(sert_val>=arr[j])
break;
//否则继续下移
arr[s]=arr[j];
s=j;
}
//插入元素
arr[s]=sert_val;
return;
}
void heap_sort()
{
//初始化大根堆
for(int i=heap_size/2;i>=1;i--)
heap_Adjust(arr,i,heap_size);
int tmp;
//输出排序结果
for(int i=heap_size;i>1;i--)
{
printf("%d\n",arr[1]);
tmp=arr[i];
arr[i]=arr[1];
arr[1]=tmp;
//每输出一个数据,堆调整的元素个数-1
heap_Adjust(arr,1,i-1);
}
}
int main(int argc,char const*argv[])
{
heap_sort();
return 0;
}