堆排序(heap sort)

什么叫做堆?

      从上图中可以看出,图中的树是一个完全二叉树;左图中根结点的值是最大的数,所有结点的值都要大于它的左右孩子,右图中根结点的值是最小的,所有结点的值都要小于它的左右孩子,这就是一个堆结构。

堆分为大顶堆和小顶堆;

大顶堆如左图所示,是一个完全二叉树,每个结点的值都大于或等于左右孩子的值;

小顶堆如右图所示,是一个完全二叉树,每个结点的值都小于或等于左右孩子的值;

堆的根结点的值一定是堆中所有结点最大的或最小的值。

 什么叫堆排序?

        堆排序就是利用堆进行排序的方法,将待排序的序列构成一个大顶堆(小顶堆),此时最大的数(最小的数)就是堆的根结点,再将根结点的值与数组中最末尾的元素进行交换,末尾就存放数组最大值(最小值),再将剩下的n-1个元素再次构造成一个大顶堆(小顶堆),这样就得到数组中第二大(第二小)的值,再次递归执行,就能将数组中的值有序排列。

如何构成一个大顶堆(小顶堆)?

以下以大顶堆为例:

      建立一个数组,建立一个个数与数组相同的二叉树,将二叉树从上到下按照层次的方法标下标;

若结点为i;数组大小为len:

左孩子下标:i*2+1

右孩子下标:i*2+2

最后一个结点下标:len/2-1

void HeapSort(int *a,int len)
{
    int i;
    for(i=len/2-1;i>=0;i--)//len/2-1是最下层的最后一个头节点的下标,-- 的每一个都是一个头节点
    {
        HeapAdjust(a,i,len-1);
    }
}
void HeapAdjust(int *a,int num,int len)
{
    int temp=a[num];
    int i;
    for(i=2*num+1;i<=len;i=2*i+1)//2*num+1左孩子;i=2*i+1下一个结点的左孩子
    {
        if(i<len && a[i]<a[i+1])//左孩子与右孩子作比较,得到大的数
        {
            i++;
        }
        if(a[i]>temp)//比较孩子数与父结点的大小
        {
            a[num]=a[i]; //子结点大于父结点与父结点作交换
            num=i;
            a[num]=temp;//如果子结点与父结点交换,将父结点的值赋给子结点
        }
    }
}

如图所示: 

堆排序 

     构成一个大顶堆后,就进行第二步将根结点的值与数组中最末尾的元素进行交换,末尾就存放数组最大值(最小值),再将剩下的n-1个元素再次构造成一个大顶堆(小顶堆),这样就得到数组中第二大(第二小)的值,再次递归执行,就能将数组中的值有序排列。

void HeapSort(int *a,int len)
{
    int temp;
    for(i=0;i<len-1;i++)
    {
        temp=a[0];
        a[0]=a[len-1-i];
        a[len-1-i]=temp;//将已经完成大堆顶的顶与最后一个值进行交换
        HeapAdjust(a,0,len-1-i-1);//将最大的数放在末尾,不再使用
    }
}

如图所示:

 总代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void HeapAdjust(int *a,int num,int len);
void HeapSort(int *a,int len);
void HeapAdjust(int *a,int num,int len)
{
    int temp=a[num];
    int i;
    for(i=2*num+1;i<=len;i=2*i+1)//2*num+1左孩子
    {
        if(i<len && a[i]<a[i+1])//左孩子与右孩子作比较,得到大的数
        {
            i++;
        }
        if(a[i]>temp)//比较孩子数与父结点的大小
        {
            a[num]=a[i]; //子结点大于父结点与父结点作交换
            num=i;
            a[num]=temp;//如果子结点与父结点交换,将父结点的值赋给子结点
        }
    }
}
void HeapSort(int *a,int len)
{
    int i;
    for(i=len/2-1;i>=0;i--)//len/2-1是最下层的最后一个头节点的下标,--的每一个都是一个头节点
    {
        HeapAdjust(a,i,len-1);
    }
    int temp;
    for(i=0;i<len-1;i++)
    {
        temp=a[0];
        a[0]=a[len-1-i];
        a[len-1-i]=temp;//将已经完成大堆顶的顶与最后一个值进行交换
        HeapAdjust(a,0,len-1-i-1);//将最大的数放在末尾,不再使用
    }

}

int main(int argc, char *argv[])
{ 
    srand(time(NULL));
    int a[9];
    int i;
    int len=sizeof(a)/sizeof(a[0]);
    for(i=0;i<len;i++)
    {
        a[i]=rand()%100;
    }
    HeapSort(a,len);
    for(i=0;i<len;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
} 

结果:

 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值