堆排序

堆排序

堆的介绍

堆是一个数组,它可以被看成一个近似的完全二叉树。树上的每一个结点对应数组中的一个元素。同时,除了最底层外,该树是完全充满的,而且是从左向右填充

最大堆与最小堆

二叉堆分为两种,即最大堆与最小堆。在最大堆中,最大堆性质是指除了根以外的所有结点i都要满足:A[PARENT(i)] >= A[i],即除根结点外的每个结点都大于或等于其子结点,下图则为一个最大堆。(图源自《算法导论》)
在这里插入图片描述

而最小堆则与之相反。

最大堆的维护

维护最大堆,即判断某个结点是否符合最大堆的性质,如若不符合,通过将其与子结点交换生成的新堆符合性质。同时,因为为除根结点外的结点,故不需对根结点进行维护,下面给出代码。

void max_heapify(int a[], int i, int n){ //n为结点数
    int l = 2 * i, r = 2 * i + 1, largest; // l,r分别为左孩子和右孩子
    if(l <= n && a[i] < a[l])
        largest = l;
    else
        largest = i;
    if(r <= n && a[largest] < a[r])
        largest = r;
    if(largest != i){
        swap(a, i, largest); //交换值以维护
        max_heapify(a, largest, n);
    }    
}
建堆

建堆过程,就是对一个不符合最大堆(最小堆)的堆进行堆维护的过程,同时,对于根结点无需进行维护,故给出如下代码。

void build_max_heap(int a[], int n){
    for(int i = n / 2; i >= 1; i--)
        max_heapify(a, i, n);
}
堆排序

在建完堆后,就可进行堆排序的过程了。堆排序的主要原理:由最大堆的性质,根结点(即第一个结点)的值必为最大,所以可将其排至末尾,即将其与末尾结点的元素进行交换,同时将堆的总元素减一,这时再对堆首元素进行一轮维护,之后反复执行此过程,可实现堆排序。具体图示过程如下(图源自《算法导论》)。
在这里插入图片描述
在这里插入图片描述

接下来给出总代码。

#include<bits/stdc++.h>
#include<stdio.h> 
#define maxn 1005000
using namespace std;

void swap(int a[], int i, int j){
    if(i != j){
        int cmp = a[i];
        a[i] = a[j];
        a[j] = cmp;    
    }
}
void max_heapify(int a[], int i, int n){ //n为结点数
    int l = 2 * i, r = 2 * i + 1, largest; // l,r分别为左孩子和右孩子
    if(l <= n && a[i] < a[l])
        largest = l;
    else
        largest = i;
    if(r <= n && a[largest] < a[r])
        largest = r;
    if(largest != i){
        swap(a, i, largest); //交换值以维护
        max_heapify(a, largest, n);
    }    
}
void build_max_heap(int a[], int n){
    for(int i = n / 2; i >= 1; i--)
        max_heapify(a, i, n);
} 
void heapsort(int a[], int n){ //堆排序
    build_max_heap(a, n);
    for(int i = n; i >= 2; i--){
        swap(a, 1, i);
        //cout << a[i] << endl;
        n -= 1;
        max_heapify(a, 1, n);
    }

}
int main()
{
    int b[11] = {0, 1, 14, 16, 9, 10, 2, 3, 8, 4, 7};
    heapsort(b, 10);
    for(int i = 1; i <= 10; i++)
        cout << b[i] << " ";
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值