排序算法之堆排序

介绍堆排序算法之前必须知道“堆”这种数据结构,堆可近似看成是一个完全二叉树,不同的是用数组中的元素从上到下,从左到右填充该树。
堆可分为最大堆和最小堆(查看定义),堆排序算法就是建立在最大堆或者最小堆基础上,通过不断取出堆顶元素,将剩下n-1个元素重新建堆,如此循环获得有序序列。所以关键在于如何建最大堆/最小堆和如何调整剩余元素为新堆。(不上图了,大家看其他博客)
堆排序用在大数据量比较有效,同时不仅用于排序,推广到取最值的引用中,例如进程调度:选取优先级最高的进程,时间调度中:取执行时间最短或者等待时间最长等等。
1.堆的存储
堆一般以数组的形式表示,i节点的父节点是(i-1)/2,子节点是2*i +1和2*i+2,例如节点0的子节点是1和2。
2.堆的操作
堆操作包括堆的插入(插入堆尾),删除及删除后调整(删除堆顶,重新调整)。堆排序是建堆后取得堆顶元素,所以,重点对删除及删除后调整进行操作。
建堆用到递归思想,堆的调整是自下往上,把i节点和它的两个子节点2*i+1和2*i+2进行比较,找出最大的节点存到i节点中,i从树的最后一个非叶子节点开始往上取,每一趟便找出最大值,如此往复。
3.实现:(VC6.0验证通过)

#include<stdio.h>

//i节点及2*i+1与2*i+2三节点找出最大值,i==start
void Adjust(int a[],int start,int len)
{
    int i,max,tmp;
    i=start;
    max=i;
    while((2*i+1)<len || (2*i+2)<len)//循环使子树都为堆
    {
        if((2*i+1)<len && a[2*i+1]>a[i])
            max=2*i+1;
        //右子节点存在的话,左子节点一定存在,所以与前两个的最大值比
        if((2*i+2)<len && a[2*i+2]>a[max])

            max=2*i+2;
        /*****选取三个数中的最大值***************
        if((2*i+1)<len && (2*i+2)<len)
        {
            if (a[2*i+2]<a[2*i+1])
                max=2*i+1;
            else
                max=2*i+2;
        }//有bug,如果只有一个子节点呢
        **************************************/
        if(a[max]>a[i])
        {
            tmp=a[max];
            a[max]=a[i];
            a[i]=tmp;
            i=max;
        }
        else 
            break;
    }
}

void Build(int a[],int len)//从下往上构造最大树
{
    int i;
    for(i=len/2-1;i>=0;i--)//len/2-1为最后一个非叶子结点
    {
        Adjust(a,i,len);
    }
}

void Heapsort(int a[],int len)//将数的根节点与尾节点交换后,重新构造树
{
    int i,tmp;
    Build(a,len);
    for(i=len-1;i>=0;i--)
    {
        tmp=a[i];
        a[i]=a[0];
        a[0]=tmp;//交换第一个值与最后一个值
        Adjust(a,0,i-1);//重新调整剩下的n-1个数
    }
}
//打印数组
print(int a[],int len)
{
    int i;
    for(i=0;i<len;i++)
        printf("%d ",a[i]);
    printf("\n");
}

void main()
{
    int a[]={5,3,4,2,6,8,1,7};
    print(a,8);
    Heapsort(a,8);
    print(a,8);
}

后续总结:堆排序首先建造堆(从下往上),取堆顶元素后,调整堆(从上往下)。建造堆时,从最后一个非叶子节点开始,与子节点比较,将最大值存储到i节点中,以此往上,构造出最大堆;将堆顶元素与堆尾元素交换后,对余下元素(除最大元素)用同样方法调整,建造新的堆…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值