堆排序

堆排序

  • 核心思想:

    • 前提知识:其实就是一种特殊的完全二叉树,分为大顶堆小顶堆,大顶堆就是指父节点>=左右孩子结点,而左右孩子结点之间的大小关系随意,小顶堆反之
    • 堆排序核心:就是先把序列构建成大顶堆序(升序用大顶堆),然后大顶堆的根节点和最后一个结点交换位置,这样一来每交换一次就得到当前序列的最大值,并把它放在了最后面,接着把剩下的序列继续构建成大顶堆,重复上面动作,直到序列只剩一个
    • 复杂度分析:

      • 最好情况:O(nlogn)
      • 最差情况:O(nlogn)
      • 平均:O(nlogn)
      • 辅助空间:O(1)
    • 稳定性:不稳定

图解

  • 注:大顶堆,小顶堆的左右孩子的大小随意

这里写图片描述

对应的在数组中的位置如下
这里写图片描述

  • 第一步,给定无序序列如下

这里写图片描述

  • 第二步,从最后一个非叶节点开始,从左至右,从上至下调整二叉树,形成大顶堆
    (注:第一个非叶节点为length/2-1,这里为arr[1]=6)

    从arr[1]处开始构建堆

这里写图片描述

接着处理arr[0]
这里写图片描述
由于交换完后,arr[1]处又乱了,继续处理arr[1]

这里写图片描述
至此,大顶堆构建完成

  • 第三步,得到大顶堆后,让大顶堆首元素和末尾元素交换,如此让最大元素处于最末位置,由于交换会导致新二叉树不满足大顶堆性质,于是要进行调整,让它重新变成大顶堆,接着又是首元素和末尾元素交换,得到第二大的元素,并排放在倒数第二的位置,如此反复执行交换,调整,交换...

交换1
这里写图片描述
调整1
这里写图片描述
交换2
这里写图片描述

后续如下
这里写图片描述
代码如下



#include <iostream>

void swap(int *&arr,int i,int j){
    int temp=arr[i];
    arr[i]=arr[j];
    arr[j]=temp;
} 

void buildHeap(int *&arr,int i,int n){//以arr[i]为根建立堆(升序大顶堆) 
    int temp=arr[i]; 
    for(int k=2*i+1;k<n;k=2*k+1){
        if(k+1<n&&arr[k]<arr[k+1]) {
            k++;
        }
        if(temp<arr[k]){
            arr[i]=arr[k];
            i=k;
        }else{
            break;  
        }
    }
    arr[i]=temp;
}
void heapSort(int arr[],int n){
    int i,j;
    for(i=n/2-1;i>=0;i--){//建好了堆 
        buildHeap(arr,i,n);
    }
    for(j=n-1;j>=0;j--){
        swap(arr,j,0);
        buildHeap(arr,0,j);
    } 
}
int main(int argc, char** argv) {
    int arr[]={4,12,35,98,4,44,58,13,15};
    heapSort(arr,9);
    for(int i=0;i<9;i++){
        printf("%d ",arr[i]);
    }
    return 0;
}

注:本文所用图均来自dreamcatcher-cx大神的博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值