堆排序

堆排序

前言

    堆排序和归并排序一样,时间复杂度都是O(nlg(n)),和插入排序相同的是具有空间的原址性:任何时候都只需要常数个额外的空间元素存储临时数据。因此堆排序可以说是结合了之前讨论的两种排序算法的优点。

    (二叉)堆又是一个数组,它可以被堪称一个近似的完全二叉树,树上的每一个节点都对应着数组中的一个元素。从图中可以看到,除了叶节点之外,该树是完全充满的,而且是从左向右的填充。很容易就能够通过一个节点得到其父节点,左孩子和右孩子。
堆

    再利用数学归纳法稍加证明,则能够得到下面的结论:对于一个堆a[n]来说,从a[n/2]到a[n]均为叶节点,a[0]到a[n/2-1]的都为根节点

堆排序原理

    最大堆是用来实现堆排序的先决条件,最大堆的概念:在最大堆中,一个节点的值小于等于其父节点的值。,最小堆的概念则正好相反,这里不再赘述。
那么这个最大堆最上面的一个根节点即整个数组最大的节点,利用这一特性即可进行排序,将最大的那个节点和位于堆最后的一个节点值交换,整个数组最大的数就移动到了堆的最后。

    在交换了之后会出现最大堆被破坏的问题,因此每次提取最大值后需要对其a[0~n-1]子堆进行维护,即最大堆维护。提取一次,维护一次,直到子堆缩小成一个元素,这时整个堆呈升序排列。

    最大堆维护:维护最大堆即针对某一结点来对堆进行调整,使堆呈现最大堆的特性。对于一个节点i,假设其左孩子为left(i),右孩子为right(i),则需要找出a[i],a[left(i)],a[right(i)]中最大值的下标,并记录这个下标为max_index,如果max_index==i,则以i为根节点的树呈最大堆状态,不必理会,否则就将a[max_index]与a[i]交换,再以max_index作为根节点,一直递归查找下去,将下面的子树都调整为最大堆状态。
最大堆维护

C语言的实现

//针对节点i进行最大堆的调整
void max_heapify(int* a, int i, int count)
{
    int left_index , right_index ;
    int max_index = i;
    left_index = 2 * i + 1;
    right_index = left_index + 1;
    if ((left_index <= count) && (a[left_index] > a[max_index]))
    max_index = left_index;
    if ((right_index <= count) && (a[right_index] > a[max_index]))
        max_index = right_index;
    if (max_index != i)
    {
        int t = a[i];
        a[i] = a[max_index];
        a[max_index] = t;
        max_heapify(a, max_index, count);
    }
}

//建立最大堆
void build_max_heap(int* a, int count)
{
for (int i = count / 2; i >= 0; i--)
    {
        //对每个子根节点进行堆调整
        max_heapify(a, i, count);
    }
}

//开始堆排序
void heap_sort(int* a, int count)
{
    int t;
    for (int i = count; i >= 1; i--)
    {
        t = a[0];
        a[0] = a[i];
        a[i] = t;
        max_heapify(a, 0, i - 1);
    }
}

void main()
{
    int count, *p;
    printf("请输入需要排序的数的个数 :");
    scanf_s("%d", &count);
    p = (int *)malloc(count * 2);
    printf("\n请输入需要排序的%d个数字:",count);
    for (int i = 0; i < count; i++)
    {
        scanf_s("%d", p+i);
    }
    //依据输入的一列数字,建出一个最大堆
    build_max_heap(p, count - 1);
    printf("建立最大堆后的数组:");
    for (int i = 0; i < count; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n\n");
    //开始堆排序
    heap_sort(p, count - 1);
    printf("堆排序后的数组:");
    for (int i = 0; i < count; i++)
    {
        printf("%d ", p[i]);
    }
    printf("\n\n");
    system("pause");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值