堆排序(按非递减规则)

文章详细介绍了堆排序的概念,以大顶堆为例,阐述了堆的定义、数组存储方式以及堆的性质。堆排序的过程包括建立初始堆、维护堆和交换堆顶元素,并通过代码示例展示了如何实现这个排序算法。此外,还提到了堆排序的时间复杂度和非递增规则排序的变体。
摘要由CSDN通过智能技术生成

堆的定义(以大顶堆为例)

一棵完全二叉树,父节点的值大于或等于左右子节点。

约定:

堆用数组存储,数组下标从1开始,从上到下、从左到右标记完全二叉树的节点。

堆下标的性质:

设父节点下标为pos,左子节点下标为lson,右子节点下标为rson。
pos=lson/2 , pos=rson/2 (向下取整的整数除法)
lson=pos*2 , rson=pos*2+1

堆排序的思路

1.将待排序序列输入到数组a中
2.建立初始大顶堆
3.设pos为最后一个节点的下标,将pos和下标1的节点元素互换(swap),达到将堆顶最大元素置于pos节点的目的,然后维护1 ~ pos-1节点所构成的堆,pos执行到第二个节点(第一个节点已经排序好了,没必要再来一次)。

维护堆

void heapify(int pos,int range)                      //维护堆,pos为起始节点下标,range控制维护范围
{
    int max=pos;
    int lson=2*pos;
    int rson=2*pos+1;
    if(lson<=range and a[max]<a[lson]) max=lson;     //与左子节点的元素作比较
    if(rson<=range and a[max]<a[rson]) max=rson;     //与右子节点的元素作比较
    if(max!=pos)                                     //判断是否需要元素交换
    {
        swap(a[max],a[pos]);
        heapify(max,range);                          //若发生了父节点与子节点的交换,则递归维护其子树
    }
}

 建立大顶堆

将pos从最后的节点下标向前移至第一个节点下标,每个pos都进行一次“维护堆”(heapify()),这一步可以优化,pos初始值改为最后一个拥有子节点的节点位置,即 pos=n/2。

for(int i=n/2;i>=1;i--) heapify(i,n);

总过程

结合“思路”,得出以下函数

void heap_sort()
{
    for(int i=n/2;i>=1;i--) heapify(i,n);
    for(int i=n;i>=2;i--)
    {
        swap(a[i],a[1]);
        heapify(1,i-1);
    }
}

例题

给定一个整数序列,请按非递减序输出采用堆排序的各趟排序后的结果。

输入格式:

测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。

输出格式:

对于每组测试,输出若干行,每行是一趟排序后的结果,每行的每两个数据之间留一个空格。

输入样例:

4
8 7 2 1

输出样例:

7 1 2 8
2 1 7 8
1 2 7 8

代码实现

#include<bits/stdc++.h>
using namespace std;
int n;
int a[101];
void output()
{
    for(int i=1;i<=n;i++)
    {
        if(i!=1) cout<<" ";
        cout<<a[i];
    }
    cout<<endl;
}
void heapify(int pos,int range)                      //维护堆
{
    int max=pos;
    int lson=2*pos;
    int rson=2*pos+1;
    if(lson<=range and a[max]<a[lson]) max=lson;     //与左字节点的元素作比较
    if(rson<=range and a[max]<a[rson]) max=rson;     //与又字节点的元素作比较
    if(max!=pos)                                     //判断是否需要元素交换
    {
        swap(a[max],a[pos]);
        heapify(max,range);                          //若发生了父节点与子节点的交换,则递归维护其子树
    }
}
void heap_sort()
{
    for(int i=n/2;i>=1;i--) heapify(i,n);
    for(int i=n;i>=2;i--)
    {
        swap(a[i],a[1]);
        heapify(1,i-1);
        output();
    }
}
int main()
{
    while(cin>>n)
    {
        for(int i=1;i<=n;i++) cin>>a[i];
        heap_sort();
    }
    return 0;
}

代码时间复杂度

非递增规则排序

思路一致,创建小顶堆,注意判断元素大小时符号也要跟着改变。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值