数据结构之堆排序算法详解+C语言实现


  堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
在这里插入图片描述
堆排序
  堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。
在数据结构中,我们将堆的逻辑结构映射到数组中存储,如下图:
在这里插入图片描述

于是在数组中,堆中节点的索引有如下定义:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

堆常用来作堆排序,主要思想如下:
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
堆排序的步骤:
一、构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。

  1. 设给定的无序序列如下:
    在这里插入图片描述
  2. 此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整。
    在这里插入图片描述
  3. 找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换
    在这里插入图片描述
  4. 如此进行下去,得到最后的大顶堆序列如下:
    在这里插入图片描述
    二、将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。
    a.将堆顶元素9和末尾元素4进行交换
    在这里插入图片描述
    b.重新调整结构,使其继续满足堆定义
    在这里插入图片描述
    c.再将堆顶元素8与末尾元素5进行交换,得到第二大元素8.
    在这里插入图片描述
    后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序
    在这里插入图片描述
    再简单总结下堆排序的基本思路:
      a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
      b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
      c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

      
    代码实现:
#include<stdio.h>
typedef int ElementType;
int arr1[11]={0,2,87,39,49,34,62,53,6,44,98};
#define LeftChild(i) (2 * (i) + 1)

void Swap(int* a,int* b)
{
    int temp=*a;
    *a=*b;
    *b=temp;
}


void PercDown(int  A[], int i, int N)	//构成堆
{
    int child;
    ElementType Tmp;

    for (Tmp = A[i]; 2*i+1 < N; i = child){
        child = 2*i+1;				 //左孩子节点
        if (child != N - 1 && A[child + 1] > A[child])
            ++child;                //找到最大的儿子节点
        if (Tmp < A[child])			//如果小于最大孩子的值,就将自己的值变为最大孩子的值
            A[i] = A[child];
        else
            break;					//否则,退出该非叶子节点的所有循环
    }
    A[i] = Tmp;
}

void HeapSort(int A[], int N)	//排序,每次都把最大数排到堆顶,然后再与最后一个未定位的点交换
								//这样就可以得到一个固定的顺序
{
    int i;
    for (i = N / 2; i >= 0; --i) //i=5,4,3,2,1,0
        PercDown(A, i, N);    //构造堆
    for(i=N-1;i>0;--i)//i=9, ... ,1
    {
        Swap(&A[0],&A[i]);        //将最大元素(根)与数组末尾元素交换,从而删除最大元素,重新构造堆
        PercDown(A, 0, i);
    }
}

void Print(int A[],int N)
{
    int i;
    for(i=0;i<N;i++)
    {
        printf(" %d ",A[i]);
    }
}
int main()
{
    int arr[10]={2,87,39,49,34,62,53,6,44,98};
    Print(arr,10);
    printf("\n");
    HeapSort(arr,10);
    Print(arr,10);
    printf("\n");
    return 0;
}

图文参考:https://www.cnblogs.com/chengxiao/p/6129630.html
代码参考:https://www.cnblogs.com/wuchanming/p/3821607.html

  • 19
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值