快速排序之-堆排序

快速排序之-堆排序

堆排序思想:对数组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;i>=1;i--)//一趟对堆的排序
        {
            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);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_42373888/article/details/81979359