基础指南 之 堆排序

堆排序

排序算法主要分三大类,交换排序有冒泡排序和快速排序,插入排序有简单插入排序和希尔排序,选择排序有堆排序和简单选择排序。其中快速排序和堆排序的时间复杂度为 o(nlogn),但这两种排序都不稳定(相等的元素在排序前后的顺序是否会发生改变)。
堆排序是一种选择排序,其原理是在序列上建立大顶堆(或者小顶堆),堆顶元素便是序列的最大值(或者最小值),将堆顶的元素放到堆尾部,再调整除堆尾部元素的其他元素,将堆重新调整成大顶堆,取出堆顶元素放在新的堆尾部,依次调整堆顶,取出最大元素,完成排序过程。

以降序的堆排序为例。

  1. 首先,构造小顶堆。
    从最后一个非叶子节点开始,从左至右,从下至上进行调整,将该非叶子节点和其子节点中数值较小的调整至非叶子节点位置。依次寻找剩余的非叶子节点进行调整。
    调整某一个非叶子节点的代码如下所示:
//堆中非叶子节点调整
void HeapAdjust(int data[],int length,int k)
{
    int tmp=data[k];
    int i=2*k+1;
    while(i<length)
    {
        //选择节点 k 的两个自节点中值较小的
        if(i+1<length && data[i]>data[i+1])
            ++i;
        //比较节点 k 与其子节点中值较小的数值
        if(tmp<data[i])
            break;
        //将较小的子节点的值交换到节点 k 中
        data[k]=data[i];
        //下一轮循环中继续调整节点k的子节点的子节点
        k=i;
        i=2*k+1;
    }
    //此时 k 是最近的一个调整过的节点
    //可能是非叶子节点(若非叶子节点的子节点都大于它,无需调整),也可能是叶子节点(非叶子节点大于其子节点,调整过)
    data[k]=tmp;
}

其中 length 是堆中元素数量, k 是待调整的非叶子节点索引,i 是节点 k 中值较小的子节点,tmp 记录了节点 k 的值。判断节点 k 与其较小子节点的大小关系,若需要调整,则还需要调整该子节点与其子节点的位置,在下一轮循环中完成,最后将最开始的节点 k 的值交换到最后一次调整的位置。
2. 排序,将堆顶元素移动到堆尾部,将堆的长度减一,重新调整堆顶,继续移动堆顶元素到尾部,堆长度减一,重新调整堆顶,循环直至堆的长度减小到 0 。代码如下所示:

//堆排序 单调递减排列
void HeapSort(int data[],int length)
{
    if(data == NULL || length <= 0)
        return;
    //建立小顶堆
    for(int i=length/2-1;i>=0;i--)
    {
        HeapAdjust(data,length,i);
    }
    //将堆顶元素移动到堆尾部,重新调整堆顶
    for(int i=length-1;i>0;i--)
    {
        swap(data[0],data[i]);
        HeapAdjust(data,i,0);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值