堆排序

堆排序是一种高效的比较排序算法,通过构建最大堆或最小堆进行排序,具有O(nlogn)的时间复杂度。文章详细介绍了堆排序的过程,包括建堆、下沉操作以及其在实际应用中的特点。
摘要由CSDN通过智能技术生成

堆排序是一种基于比较的排序算法,它使用二叉堆(特殊的完全二叉树)的数据结构来实现。二叉堆可以是最大堆或最小堆,其中最大堆的父节点总是大于或等于子节点,而最小堆的父节点总是小于或等于子节点。

基本思想:

  • 构建堆:首先将无序的输入序列构造成一个最大堆或最小堆。
  • 排序:通过交换堆顶元素(最大或最小)与堆的最后一个元素,然后从堆中移除该元素(即原堆的最后一个元素),并重新调整堆的结构,使其继续保持最大堆或最小堆的性质。这个过程重复进行,直到堆中只剩下一个元素。

操作步骤:

  1. 建堆(Heapify)

    • 从最后一个非叶子节点开始,向上遍历至根节点。
    • 对于每个节点,确保它满足堆的性质(即在最大堆中,父节点的值大于子节点的值;在最小堆中,父节点的值小于子节点的值)。
    • 如果节点不满足堆的性质,通过与其子节点中的较大(或较小)者交换来调整堆。
    • 重复这个过程,直到建堆完成。
  2. 排序

    • 将堆顶元素(最大或最小值)与堆的最后一个元素交换。
    • 移除堆中原来的最后一个元素(已经与堆顶元素交换)。
    • 对新的堆顶元素进行下沉操作(在最大堆中向下调整,在最小堆中向上调整),以恢复堆的性质。
    • 重复上述步骤,直到堆中只剩下一个元素。

堆排序的时间复杂度为O(n log n),其中n是序列的长度。建堆的过程是O(n)的,而每次的下沉操作是O(log n)的,由于排序过程中需要进行n次下沉操作,因此总的时间复杂度为O(n log n)。

堆排序是一种原地排序算法,不需要额外的存储空间,但它不是稳定的排序算法,因为相同的元素可能会在堆调整过程中改变顺序。堆排序适用于大数据集的排序,特别是当内存使用成为一个考虑因素时。

输入格式

  • 第一行:包含两个整数 n 和 m(1 <= n,m <= 100000)
    • n 表示整数数列的长度。
    • m 表示需要输出的前 m 小的数。

第二行

  • 包含 n 个整数,表示整数数列中的每个数。

输出格式

  • 输出一行,包含 m 个整数。
  • 这些整数是整数数列中的前 m 小的数,按照从小到大的顺序排列。
输入样例:
5 3
4 5 1 3 2
输出样例:
1 2 3
#include<iostream>
using namespace std;

const int N = 100010; // 定义常量N,表示堆的最大容量

int h[N], n, m; // h数组用于存储堆的元素,n表示堆中元素的数量,m表示操作的次数

// heap函数用于维护堆的性质,x是当前节点的索引
void heap(int x)
{
    int u = 2 * x; // u是x的左子节点的索引
    if(u + 1 <= n && h[u + 1] < h[u]) u = u + 1; // 如果有右子节点,并且右子节点的值小于左子节点的值,则选择较小的子节点
    if(u <= n && h[u] < h[x]) // 如果子节点的值小于父节点的值
    {
        int t = h[u]; // 交换父节点和子节点的值
        h[u] = h[x];
        h[x] = t;
        heap(u); // 递归调用heap函数,继续向下调整
    }
}

int main()
{
    cin >> n >> m; // 输入n和m
    for(int i = 1; i <= n; i ++) cin >> h[i]; // 输入堆中的元素
    // 从最后一个非叶子节点开始向上建立最小堆
    for(int i = n / 2; i >= 1; i --) heap(i);
    while(m --) // 处理m次操作
    {
        cout << h[1] << " "; // 输出堆顶元素(最小元素)
        h[1] = h[n --]; // 将堆顶元素替换为堆的最后一个元素,并减少堆的大小
        heap(1); // 重新调整堆以维护其性质
    }
    return 0; // 程序结束
}

 

总结

堆排序是一种高效的比较排序算法,它利用二叉堆(最大堆或最小堆)的性质来对序列进行排序。算法首先将给定的序列构造成一个堆,然后将堆顶元素(最大或最小值)与最后一个元素交换并从堆中移除,接着重新调整堆以维持其性质。这个过程重复进行,直到堆中只剩下一个元素,从而实现从小到大的排序。堆排序的时间复杂度为O(n log n),是原地排序算法,不需要额外的存储空间,但在排序过程中相同元素的相对顺序可能会改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值