【排序算法】堆排序(图解)

堆排序

堆排序Heapsort是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:
即子结点的键值或索引总是小于(或者大于)它的父节点。
首先要说一下什么是完全二叉树:

  • 每个节点最多有两个子节点(左,右儿子)
  • 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层从左边第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

注意完全二叉树有一个性质:最后一个父结点是第n/2个结点。

然后我们回过头来说算法:
首先看一下堆排序的图片演示
在这里插入图片描述
算法步骤:

  1. 将初始待排序数组(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
  2. 从最后一个非父节点开始,依次调整堆为大顶堆,若调整过程中,某次交换元素后与子节点不构成大顶堆,那么就进行这个堆的调整
  3. 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
  4. 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
    文字说明可能会有点枯燥,接下来用图片讲解
    在这里插入图片描述
    找到最后一个父节点(n/2),将这个最小堆进行调整变为大顶堆结果如下图:
    在这里插入图片描述
    接着找倒数第二个父节点(往前1个),将其调整为大顶堆
    在这里插入图片描述
    经过调整,最后一个父节点所在行的所有父节点都变成大顶堆
    在这里插入图片描述
    继续往前(此时调整R[3])
    在这里插入图片描述
    发现本来就是一个大顶堆,不需要调整,继续往前,看R[2]
    变为

然后看R1
变为
各个节点都满足大顶堆,就将最后一个元素与堆顶交换
在这里插入图片描述
交换后,发现堆顶不是大顶堆,然后接着往下调整
变为

此时下图这个堆也不满足大顶堆,继续往下调整。
变为
变为

在这里插入图片描述
重复此操作,将整个变换成有序堆。
代码如下:

#include <iostream>
#define N 1000
using namespace std;

int arr[N];
void Print(int n)
{
    cout << arr[1];
    for(int i=2;i<=n;i++)
    {
        cout << " " << arr[i];
    }
    cout << endl;
}
void adjust(int p, int n)
{
    int t = 0, flag = 0;
    while (p * 2 <= n && flag == 0)
    {
        if (arr[p] < arr[p * 2]) //先判断左儿子
            t = p * 2;
        else
            t = p;
        if (p * 2 + 1 <= n) //看是否存在右儿子
            if (arr[t] < arr[p * 2 + 1])
                t = p * 2 + 1;

        
        if (t != p)//如果最大的不是自己 就进行交换
        {
            swap(arr[t], arr[p]);
            p = t;//最大的改为 t 方便进行接下来的调整
        }
        else
            flag = 1;
    }
}
void HeapSort(int n)
{
    for (int i = n / 2; i >= 1; i--)
    {//从最后一个父节点开始调整
        adjust(i, n);
    }
    while (n > 0)
    {
        swap(arr[1], arr[n]);//与最后一个交换
        n--;
        adjust(1, n);
    }
}
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> arr[i];
    }
    HeapSort(n);
    Print(n);
}

感谢您的观看

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值