算法_选择排序之堆排序

什么是堆?

堆的概念:所有分支结点都大于(小于)其孩子结点的完全二叉树称为大(小)根堆。

因此,大(小)根堆的根结点必定是最大(小)元素。利用简单选择排序的思路,就可以每次从大(小)根堆中选取根结点,使元素序列有序。

思路

堆排序是一种树形选择排序方法,它的特点是将元素序列看成是一个完全二叉树的顺序存储结构,利用堆的性质对元素进行排序。

实现

void heap_sort(RceType R[], int n)
{
    int i;
    //构建初始堆
    for (i=n/2; i>=1; i--)
        sift(R, i, n);
    for (i=n; i>1; i--)
    {
        swap(R, 1, i);
        sift(R, 1, i-1);
    }
}

void sift(RecType R[], int low, int high)
{
    int i = low, j = 2 * i;
    RecType tmp = R[i];
    while (j <= high)
    {
        if (j < high && R[j].key < R[j+1].key)
            j++;
        if (tmp.key < R[j].key)
        {
            R[i] = R[j];
            i = j;
            j = 2 * i;
        }
        else
            break;
    }
    R[i] = tmp;
}

算法分析

时间复杂度

假设元素序列有n个元素,那么元素序列构成的完全二叉树高度h为
⌈log2(n+1)⌉或⌊log2n⌋+1 \lceil log_2(n+1) \rceil 或 \lfloor log_2n \rfloor + 1 log2(n+1)log2n+1
高度为h的完全二叉树对根结点进行筛选,则最多需要进行2(h-1)次比较,最多(h+1)次移动(因为比较与移动次数是同一个数量级,且移动次数较多,所以针对比较次数来分析时间复杂度)。


算法分为主要分为两步:

  1. 构建初始堆
  2. 重建堆

  • 最坏时间复杂度分析

最坏的情况就是构建初始堆的时候,每个分支结点都需要且都进行最大次数的筛选。则对于第i层,某个结点作为根结点的子树的高度为
(h−i+1) (h-i+1) (hi+1)
此层结点总数为
2i−1 2^{i-1} 2i1

所以构建初始堆的最大比较次数为
∑i=h−112i−1∗2(h−i+1−1)=∑1h−12i∗(h−i)=4n \sum _{i=h-1}^{1}2^{i-1} * 2(h-i+1-1) = \sum _1^{h-1}2^{i} * (h-i) = 4n i=h112i12(hi+11)=1h12i(hi)=4n
重建堆的最大比较次数为
∑i=2n2∗(⌈log2(i−1)+1⌉−1)<2nlog2n \sum _{i=2}^n2 * (\lceil log_2{(i-1)+1} \rceil -1) < 2nlog_2n i=2n2(log2(i1)+11)<2nlog2n
所以堆排序的最大比较总次数(也就是最坏时间复杂度)为
4n+2nlog2n=O(nlog2n) 4n + 2nlog_2n = O(nlog_2n) 4n+2nlog2n=O(nlog2n)
堆排序和简单选择排序一样,其时间性能与初始序列的顺序无关,所以堆排序的最好、最坏和平均时间复杂度都为
O(nlog2n) O(nlog_2n) O(nlog2n)

空间复杂度

堆排序是一个就地排序算法,所以时间复杂度为
O(1) O(1) O(1)

稳定性

不稳定

适用情况

由于构建初始堆的比较次数较多,所以堆排序不适用于数据量少的情况,相反较适用于数据量大的情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值