数据结构和算法 堆排序 (图解堆调整)

什么是堆?

:是一种特殊的序列 并且 将该序列想象为 完全二叉树

元素满足

  • (ki <= k2i && ki <= k2i+1) 每个结点一定比它的左右孩子小 这种堆称为 最小化堆(小堆) (树根是最小的)
  • (ki >= k2i && ki >= k2i+1) 每个点一定比它的左右孩子大 这种堆称为 最大化堆(大堆) (树根是最大的)

堆排序(以最大化堆为例

堆调整(堆的初始化):排序之前需要将序列调整为 (不满足时 与 左右孩子中较大的那一个进行交换) 从n/2向下取整个点开始由后向前调整直到满足堆条件为止。

排序

  1. 从堆顶取出最大元素 ,堆顶元素与堆的最后一个元素交换位置 (往后就不用考虑当前最后一个元素)。
  2. 对剩余的元素进行调整 , 调整选择剩下元素中的最大元素 (根与左右孩子中较大的那个进行交换直到满足条件为止)即 对进行堆调整。
  3. 重复以上过程 直到序列有序为止 (大堆升序)。

例子 (堆调整过程)

初始序列为:5 4 8 0 9 3 2 6 7 1

1.画出该序列完全二叉树

2.找到n/2向下取整的点 本例为 (9)从后往前逐个调整

  • 0 < 6 同时 0 < 7 因为 7 > 6 故 0 与 7 交换 ;满足条件 。

    8满足条件 继续 4 < 7 同时 4 < 9 因为 9 > 7 故 4 与 9 交换 ;满足条件。

  • 5 < 9 同时 5 < 8 因为 9 > 8 故 5 与 9 交换 ;此时 5 < 7 不满足 5与7 交换 ;此时 5 <
    6 不满足 5与6 交换;满足条件。

  • 堆排序

参考上述排序过程。

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

typedef long long ll;
using namespace std;

const int N = 1010;
int n;
int a[N];
void mheap(int a[],int x,int m)
{
    int temp;
   while((2*x <= m && a[x] < a[2*x]) || (2*x+1 <= m && a[x] < a[2*x+1])) // 小于左右孩子 并且  防止越界
   {
        temp = a[2*x] >= a[2*x+1]||2*x == m ? 2*x:2*x+1;  // 比较左右孩子取较大的那个,也可能存在只有左孩子
        swap(a[x],a[temp]);
         x = temp;
    }
}

void heapsort(int a[],int len)
{
   for(int i = len/2;i >= 1;i--)
           mheap(a,i,len); //对n/2向下取整由后往前调整
           
   for(int j = len;j >= 2;j--)
    {
        swap(a[1],a[j]);
        mheap(a,1,j - 1); //对根节点调整
    }
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    cin >> n;
    for(int i = 1;i <= n;i++) cin >> a[i];
    heapsort(a,n);
    for(int i = 1;i <= n;i++)
        cout << a[i] <<' ';
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值