数据结构与算法学习-堆排序

堆排序:
堆的标准定义如下:
n个元素的序列{k1, k2, …, kn}当且仅当满足以下关系时,称为堆。
(Ki<=K2i&&Ki<=K2i+1)或(Ki>=K2i&&Ki>=K2i+1)
(i = 1, 2, ..., n/2)
可以简单理解为就是一个完全二叉树,但是比较特殊,即完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。
示例:

小顶堆:意思就是堆顶的值是最小的
大顶堆:意思就是堆顶的值是最大的
知道了堆的性质,我们自然可以推出怎么排序,首先需要把输入的数组构建成一个小顶堆/大顶堆,只需要每次把堆顶和无序的最后一个元素交换,然后更新堆,再交换,再更新。。。。就可以达到有序了。
具体步骤:
1. 先将输入的数据构建成小顶堆/大顶堆
2. 将堆顶a[1]和最后一个元素a[i]交换,i–
3. 更新堆,使其重新成为小顶堆/大顶堆
4. 一直重复第2步和第3步,直到i==1为止。
代码如下:

#include <iostream>
using namespace std;
#include <cstdio>
int min(int x, int y)
{
    if(x < y)
        return 0;
    return 1;
}
void HeapAdjust(int a[], int s, int m) //调整堆,使其有序
{
    int temp = a[s];
    for(int j = 2*s; j <= m; j *= 2)
    {   
        if(j < m && min(a[j+1], a[j]))
        {
            j++;
        }
        if(!min(a[j], temp))    break;
            a[s] = a[j];
        s = j;      
    }
    a[s] = temp;
}
void HeapSort(int a[], int len)
{
    for(int i = len/2; i > 0; --i)  //先将输入的乱序数组构建成堆,对应第1步
    {
        HeapAdjust(a, i, len);
    }
    for(int i = len; i > 1; --i)  //交换a[1]和a[i]的值,更新堆。对应第2,3步
    {
        int temp = a[1];
        a[1] = a[i];
        a[i] = temp;
        HeapAdjust(a, 1, i-1);
    }
}
int main()
{
    int a[11] = {0};
    for(int i = 1; i <= 10; i++)
    {
        scanf("%d", &a[i]);
    }
    HeapSort(a, 10);
    for(int i = 1; i <= 10; i++)
    {
        printf("%d\n", a[i]);
    }
    return 0;

}

以该图为例:

第一步我们输入{13,38,27,49,76,65},希望输出升序排列,即{13,27,38,49,65,76}
第二步先构建成大顶堆。HeapAdjust(a, 3, 6),比较27和65的大小,27<65,则两者互换。HeapAdjust(a, 2, 6),比较49和76的大小,再将其中的较大者和38比较,于是76和38互换。HeapAdjust(a, 1, 6),比较76和65的大小,再将其中较大者和13比较,于是76和13互换,此时的13比它的子结点小,于是又进行了一次互换,将49和38的较大者和13互换了。此时就得到了一个大顶堆。

第三步将76和27互换,HeapAdjust(a, 1, 6-1),将65和49做比较,取较大者和a[1]的27交换,完成了第一次更新。将65和38互换位置,HeapAdjust(a, 1, 5-1),由于38比它的子结点小,于是又要做交换,将49和38做交换,完成了第二次更新。将49和13互换位置,HeapAdjust(a, 1, 4-1),38和27做比较,将较大者和13互换位置,即38和13互换,完成了第三次更新。将38和27互换位置,此时27就是最大元素了,完成了第四次更新。将27和13交换,此时只剩下13最后一个元素,完成了第五次更新,达到有序。

最后还有一点,堆排序适用于大文件,而不适用于小数据。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值