数据结构第九周笔记(3)——排序(上)(慕课浙大版本--XiaoYu)

86 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第21天,点击查看活动详情

9.3 堆排序

概念

大顶堆:每个节点的值都大于或者等于它的左右子节点的值。
​
堆排序的基本思想是:
1、将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素;
2、将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;
3、重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。最后,就得到一个有序的序列了。

9.3.1 选择排序

void Selection_Sort( ElementType A[],int N )
{
    for( i = 0;i < N; i++ ){
        MinPosition = ScanForMin( A,i,N-1);
        //从A[i]A[N-1]中找最小元,并将其位置赋给MinPosition
    Swap(A[i],A[MinPosition]);//这两个元素通常情况下不是挨着的,可能跳了很远的距离做一个交换,一下子就消除掉很多逆序对
        //将未排序部分的最小元换到有序部分的最后位置
        //最坏情况就是每次都必须换一下,最多需要换N-1次
    }
}
//想要得到更快的算法取决于这个ScanForMin( A,i,N-1),也就是如何快速找到最小元

image-20220818001442455

最小堆的特点就是他的根结点一定存的是最小元

9.3.2 堆排序

算法1:

void Heap_Sort(ElementType A[],int N)
{
    BuildHeap(A);//O(N)
    for( i = 0;i < N;i++ )
        TmpA[i] = DeleteMin(A);//把根结点弹出来,依次存到这个临时数组里面。O(logN)
    for( i = 0;i < N;i++ )//O(N)
        A[i] = TmpA[i];//将TmpA里面所有的元素导回A里面
}
//缺点:需要额外O(N)空间,并且复制元素需要时间

算法2:

void Heap_Sort(ElementType A[],int N )
{
    for(i = N/2;i >= 0;i-- ){//BuildHeap,i对应的是根节点所在的位置,N对应的是当前这个堆里一共有多少个元素
        PercDown(A,i,N);
    for( i = N-1;i > 0;i--){//堆循环
        Swap(&A[0],&A[i]);//DeleteMax,A[0]根节点里面存的是最大的元素,i是当前最后一个元素的下标,把根节点换到当前这个堆的最后一个元素的位置上去
        PercDown(A,0,i);//调整的时候是以0为根节点,i是当前这个最大堆的元素个数
    }
    }
}

在堆排序中,元素下标从0开始。则对于下标为i的元素,其左、右孩子的下标分别为:2i+1, 2i+2

image-20220818003410802

算法2的动态变化:

image-20220818003617976image-20220818003655108image-20220818003743315image-20220818003817239image-20220818003836433image-20220818003917597image-20220818003933416

堆排序
void Swap( ElementType *a, ElementType *b )
{
     ElementType t = *a; *a = *b; *b = t;
}
 
void PercDown( ElementType A[], int p, int N )
{ /* 改编代码4.24的PercDown( MaxHeap H, int p )    */
  /* 将N个元素的数组中以A[p]为根的子堆调整为最大堆 */
    int Parent, Child;
    ElementType X;
​
    X = A[p]; /* 取出根结点存放的值 */
    for( Parent=p; (Parent*2+1)<N; Parent=Child ) {
        Child = Parent * 2 + 1;
        if( (Child!=N-1) && (A[Child]<A[Child+1]) )
            Child++;  /* Child指向左右子结点的较大者 */
        if( X >= A[Child] ) break; /* 找到了合适位置 */
        else  /* 下滤X */
            A[Parent] = A[Child];
    }
    A[Parent] = X;
}
​
void HeapSort( ElementType A[], int N ) 
{ /* 堆排序 */
     int i;
      
     for ( i=N/2-1; i>=0; i-- )/* 建立最大堆 */
         PercDown( A, i, N );
     
     for ( i=N-1; i>0; i-- ) {
         /* 删除最大堆顶 */
         Swap( &A[0], &A[i] ); /* 见代码7.1 */
         PercDown( A, 0, i );
     }