快速排序之-堆排序
堆排序思想:对数组a[1]…a[n-1],进行一次排序使得得数组堆顶部a[1]关键字最大(或最小关键字),然后堆顶a[1]与数组末端关键字a[n-1]交换,对a[1]…a[n-2]进行相同的堆排序,排完序后啊a[1]最小,将a[1]与a[n-2]进行交换,对数组a[1]…a[n-3]按如上规则进行排序,交换,,,最后整个数组依次遍历完成后就得到一个由小到大的数组排序a[1],a[2]….a[n-1]
这里简单介绍一下堆排序的关键算法思想:因为堆排序首先是一棵完全二叉树,所以堆排序的父亲结点的数组为a[i],那么左子树结点的数组为 a[2*i],右子树的结点是a[2*i+1],如果最大关键字(该父亲节点和对应的子节点中的最大数)存在于子节点中,就将父亲节点与该子节点进行交换,反之不作任何变换。又因为数组排序的叶子结点都在后半部分,非叶子结点都在数组的前半部分,则对非叶子结点从右到左依次遍历一遍,然后在从左到右依次遍历一遍即可,下面是一个具体例子,读者可结合实例进行理解。
如下例子:初始数组为{10,6,9,3,11},按照数组顺序建立相应的初始树状图如下:
依次比对非叶子结点{6,10},对于结点6,依次比较其左右子树关键字值,如果子节点比父节点大,则两者相互交换,反之,不作任何处理,通过比对得到,11比6大,交换两点数值得到如下树状图
接下来比较结点10与其子节点(11,9),子节点11比结点10要大,所以交换子节点11与结点10的位置即可,如图所示
最后在逆推一遍(从根节点到非叶子结点),检查是否满足这种请况,发现结点10大于其任何子节点,故不需要做任何处理,一趟遍历结束后,就得到了我们的”最大堆”.得到数组(11,10,9,3,6),将最大堆堆点11与数组最右边结点6交换,,就变成了(6,10,9,3,11),接下来对数组(6,10,9,3,)按照如上规则进行排序得到最大堆(10,6,9,3),将10与结点3进行交换得到(3,6,9,10),然后对(3,6,9)按照如上规则进行排序得到(9,6,3),将9与3进行交换得到(3,6,9),然后对(3,6)按如上规则进行排序得到(6,3),结点6与3交换得到(3,6),将结点6提出,只剩下(3)结束遍历,后面得到(3,6,9,10,11)的整体数组排序
//堆排序:将数组里相应的非叶子节结点依次与左右结点比较,择取大的录入,顺推完一遍,再逆推一遍即可
void pai(int a[],int n)//里面存储的数组顺序为a[1],a[2],a[3],,,a[n-1].
{
if(n>2)
{
int t=(n-1)/2
for(i=t
{
if(a[i]<a[i*2])
{
term=a[i]
a[i]=a[2*i]
a[2*i]=term
}
if(2*i+1<n)//存在最后面一个叶子结点是右端结点
{
if(a[i]<a[i*2+1])
{
term=a[i]
a[i]=a[2*i]
a[2*i]=term
}
}
}
//将最大结点与末尾结点进行交换
term=a[1]
a[1]=a[n-1]
a[n-1]=a[1]
n--
pai(a,n)
}
}