高级排序之堆排序

时间:2022-01-20 22:09:43

概念补充:

二叉树:是n个结点的有限集合,该集合或为空(空二叉树),或者由一个根节点和两颗互不相交的、分别称为根节点的左子树和

右子树的二叉树组成

完全二叉树:

高级排序之堆排序

以上是完全二叉树,具有n个节点的二叉树按层序遍历,如果i的节点与同样深度的满二叉树编号为i的节点位置

完全相同,则这个二叉树为完全二叉树

性质5:如果一个有n个节点的完全二叉树,的节点按层序编号,,对任意节点(1<=i<=n)

如果i=1,节点i是二叉树的根,无双亲,如果i>1,则其双亲节点是i/2

如果2i>n,该节点无左子树,否则其左节点是2i

如果2i+1>n,该节点无右子树,否则其右节点是2i+1


堆是具有以下特殊性质的完全二叉树:

每个节点的值都大于等于左右孩子节点,大顶堆

每个节点的值都小于等于左右孩子节点,小顶堆

按层序遍历的方式,给节点从1开始编号,节点间满足下列关系

ki>=k2i 或者ki<=k2i

ki>=k2i+1ki<=k2i+1(1<=i<=n/2)

堆排序算法:将待排序序列构造成大顶堆,此时整个序列最大值为根节点,将其与堆数组中的末尾元素交换,

此时末尾元素就是最大值,然后将剩余的n-1个节点的序列构造成大顶堆,如此反复。

堆排序代码:

void HeapSort(arr *L)
{
    int i;


//构建大顶堆
    for ( i=L->length/2;i>0;i-- )
    {
        HeapAdjust(L,i,L->length);
    }


    for ( i=L->length;i>1;i-- )
    {

//将大顶堆的根节点与最后一个节点交换
        swap(L,1,i);

//交换后的序列重新调整为大顶堆
        HeapAdjust(L,1,i-1);
    }
}

//L序列L->data[s...n]之间除了r->data[s]之外均满足堆的定义

//本函数调整L->data[s]的关键字,使之满足大顶堆

void HeapAdjust(arr *L,int s, int n )
{
    int i,j;
    int temp;

    temp=L->data[s];
    for ( i=2*s;i<=n;i*=2 )
    {
    if( i<n && (L->data[i] < L->data[i+1]) )
        {
            i++;
        }
        if ( temp >= L->data[i] )
        {
            break;
        }
        L->data[s]=L->data[i];
        s=i;
    }


    L->data[s]=temp;
}


以{50,10,90,30,70,40,80,60,20}为待排序序列讲解

L->data:50 10 90 30 70 40 80 60 20

高级排序之堆排序

s=length/2=9/2=4,n=9,既节点30的调整,

变量j以2*s开始,又是以j*=2递变,是根据二叉树的性质5,当前节点为s,其左孩子是2*是,右孩子是2*s+1,

他们的孩子也是以2的位数序数增加。

temp=data[4]=30

i=2*s=8,i<n

左右孩子对比,找出大的孩子, data[j]<data[j+1];

高级排序之堆排序

j=8<n, 60>20,j=8

30<60,s=j,data[s=4]=data[j=8],既将左孩子放到双亲节点处

高级排序之堆排序

j=16>n,s=8,data[s=8]=temp=30

高级排序之堆排序

以上为一个节点的调整

接下来同样的方法对i=3,90节点做调整,i=2,10节点作调整,

i=1,50节点做调整

s=1,m=9

高级排序之堆排序

temp=data[s=1]=50

j=2*s=2左右孩子对比10<90,j++

j=3, temp<data[j],data[s]=data[j]

高级排序之堆排序

s=3,

j=2*s=6左右孩子对比,40<80,j++

j=7,temp<data[j=7]

高级排序之堆排序

s=7,j=2*s=14

j>n=9,退出for循环

data[s=7]=temp=10

高级排序之堆排序


通过对不是叶子节点的节点做调整,将该数组做成一个大顶堆的完全二叉树数组。

将根节点90与最后一个接点交换,并重新调整

下一次length=8,调整将9排除数组树外,既最大值在数组的最右边

for(i=length/2;i>0;i--)

我们所谓的将待排序的序列构建成一个大顶堆,其实就是从下往上,从右到左,将每个非

终端节点当做根节点,将其子树调整成大顶堆。

最小的非终端节点,n/2


堆排序时间复杂度分析:

构建堆的过程,时间复杂度为O(n)

正式排序时,时间复杂度为O(nlogn)

总体来说,堆的时间复杂度为O(nlogn)

堆排序对原始记录的排序状态并不敏感,因此它的最好,与最坏平均时间复杂度均为O(nlogn)

因为初始构建堆所需的比较次数较多,因此堆排序不适合排序序列个数较少的情况