最近在复习排序方法,学到堆排序的时候有点混乱,所有写一写梳理一下。
(以最大堆为例)
简单来说,堆排序就是先创建一个最大堆,再对所有的非叶结点进行这样的操作:将其与此时的根结点调换位置,再使该结点满足最大堆定义。
最终就完成了对数组中存储的数据的排序,数组中的数据就是按顺序存储的。
下面结合代码说一说:
(在理解代码时,最好脑中想着一个完全二叉树的样子,光想数组的话不好理解)
这个函数是使某结点满足最大堆定义,是创建堆和进行堆排序的工具
void CreateHeap(int a[],int root,int length) //使非叶结点root满足最大堆定义
//前提是其左右孩子已经都是最大堆
{
int i,j,flag;
int temp;
i=root; //i为要建堆的结点下标
j=2*i+1; //j是要建堆结点的左孩子
temp=a[i]; //先把当前结点值保存在temp中
flag=0; //是否满足最大堆的标志 为避免交换导致已调整好的子树不满足最大堆定义
while(j<length && flag!=1) //沿较大孩子向下筛选,找到所有孩子中最大的那个
{
if(j<length-1 && a[j]<a[j+1])
j++; //令j表示较大孩子
if(temp>a[j]) //若当前结点值大于较大孩子
flag=1; //标志该结点已满足最大堆定义
else //若当前结点值小于等于较大孩子,则该结点不满足最大堆定义,要将较大孩子与该结点调换
{
a[i]=a[j]; //把较大孩子值赋给当前结点
i=j; //令较大孩子变成当前结点
j=2*i+1; //j是较大孩子的左孩子,准备进入下一次循环,开始判断这个左孩子是否满足最大堆定义
}
}
//此时已经找到最大孩子,保存在a[i]中,接下来将最初保存在temp中的a[i]]值赋给原来最大孩子所在的位置
a[i]=temp;
}
然后进行堆排序
(看这个时感觉思路比较顺畅)
void Heapsort(int a[],int n) //堆排序
{
int i,j;
int temp;
//先创建一个最大堆
for(i=(n-2)/2;i>=0;i--) //使第一个非叶结点到根结点都满足最大堆定义
CreateHeap(a,i,n);
//然后正式进行排序:
//先使原先最大堆里的根结点出来,使未排序的数据形成一个新的最大堆,再使此时的根结点出来......
for(i=n-1;i>0;i--)
{
//堆顶元素与最后一个交换
temp=a[0];
a[0]=a[i];
a[i]=temp;
CreateHeap(a,0,i); //使此时的根节点满足最大堆定义
}
//排好序的结点会从数组最后依次进入,最终数组中存储的是从小到大排序的数据
}
光看代码理解的话还是有些辛苦,建议能找个流程图或者自己画个图去真正地走一遍全过程,那样思路就清晰了。
希望能有所帮助,如果有错误的部分可以在评论里发出来,一定及时纠正。