码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 第八章 排序 七、堆排序


    目录

    一、堆的概念

    1、大根堆

    2、小根堆

    二、建立大根堆

    1、举个例子,我们要让一个序列变换成为一个大根堆

    2、我们把序列看成一棵完全二叉树,而完全二叉树有以下特性:

    3、在此序列中,由于是从1开始的序列,所以分支结点为1到4

    4、我们从后往前检查,首先就检查下标为4的结点09

    5、下一个检查结点78,通过比较发现87为更大的孩子,于是进行互换

    6、继续检查结点17,通过比较发现45为更大的孩子,于是进行互换

    7、之后检查结点53,通过比较发现87为更大的孩子,于是进行互换

    8、最后再次检查结点53,通过比较发现78为更大的孩子,于是进行互换

    9、最终我们得到了一个大根堆

    三、建立大根堆的代码实现

    四、堆排序算法思想

    五、例子

    1、我们有如下序列,我们要将此序列使用堆排序进行升序排序

    2、让序列首尾元素互换,如此一来,我们就将最大元素放到了队尾。

    3、可是现在的序列又失去了大根堆的特性,所以我们要重新将它化为大根堆,只是这次我们要把87排除在外,因为它已经排好序了

    4、这次我们又让序列中的首尾元素互换,也就是78和53,将第二大的元素找到

    5、再次进行大根堆化

    6、再次首尾互换

    7、经历n-1次处理,就能得到最终的升序序列

    六、代码实现

    七、验证

    八、算法效率分析

    九、稳定性

    十、总结


    一、堆的概念

    1、大根堆

    简单来说,大根堆就是根结点均大于它的左右孩子结点的一棵完全二叉树

    2、小根堆

    同样的,对与小根堆来说,它就是根结点均小于它的左右孩子结点的一棵完全二叉树

    二、建立大根堆

    1、举个例子,我们要让一个序列变换成为一个大根堆

    2、我们把序列看成一棵完全二叉树,而完全二叉树有以下特性:

    1. 分支结点的下标为[0 到 \frac{n}{2}]
    2. 若一个结点的下标为i,则它的左孩子下标为2i,右孩子下标为2i-1,父节点的下标为\frac{i}{2}.

    3、在此序列中,由于是从1开始的序列,所以分支结点为1到4

    我们要检查每个分支结点的左右孩子是否满足大根堆的特性,根>=左右。

    4、我们从后往前检查,首先就检查下标为4的结点09

    它的左孩子为32,无右孩子,而且32大于9,不满足大根堆的特性,所以让9和32互换,若左右孩子都更大,则取更大的那个。

    5、下一个检查结点78,通过比较发现87为更大的孩子,于是进行互换

    互换后为下图

    6、继续检查结点17,通过比较发现45为更大的孩子,于是进行互换

    互换后为下图

    7、之后检查结点53,通过比较发现87为更大的孩子,于是进行互换

    互换后为下图

    但是互换后又有新的问题出现了,以53为根的子树再次不满足大根堆的特性,于是我们要继续互换。(小元素不断”下坠“)

    8、最后再次检查结点53,通过比较发现78为更大的孩子,于是进行互换

    9、最终我们得到了一个大根堆

    三、建立大根堆的代码实现

    1. void HeadAdjust(int a[],int k,int len){//k是分支结点的边界
    2. a[0] = a[k];//将分支结点存在下标为0的地方
    3. for (int i = 2*k; i <= len; i*=2) {//检查左孩子
    4. if (i1]){//找到更大的孩子
    5. i++;
    6. }
    7. if(a[0]>=a[i]){//满足大根堆特性
    8. break;
    9. }else{//不满足就交换
    10. a[k] = a[i];
    11. k = i;
    12. }
    13. }
    14. a[k] = a[0];
    15. }
    16. void BuildMaxHeap(int a[],int len){
    17. for (int i = len/2; i > 0; i--) {//遍历所有的分支结点
    18. HeadAdjust(a,i,len);//调用函数对序列进行大根堆化
    19. }
    20. }

    四、堆排序算法思想

    每次都将大根堆的序列第一个元素和序列最后一个元素互换。

    五、例子

    1、我们有如下序列,我们要将此序列使用堆排序进行升序排序

    2、让序列首尾元素互换,如此一来,我们就将最大元素放到了队尾。

    3、可是现在的序列又失去了大根堆的特性,所以我们要重新将它化为大根堆,只是这次我们要把87排除在外,因为它已经排好序了

    4、这次我们又让序列中的首尾元素互换,也就是78和53,将第二大的元素找到

    5、再次进行大根堆化

    6、再次首尾互换

    7、经历n-1次处理,就能得到最终的升序序列

    六、代码实现

    1. #include "bits/stdc++.h"
    2. using namespace std;
    3. void HeadAdjust(int a[],int k,int len){//k是分支结点的边界
    4. a[0] = a[k];//将分支结点存在下标为0的地方
    5. for (int i = 2*k; i <= len; i*=2) {//检查左孩子
    6. if (i1]){//如果该分支结点满足大根堆的特性
    7. i++;//就检查下一个分支结点
    8. }
    9. if(a[0]>=a[i]){//满足大根堆特性
    10. break;
    11. }else{//交换
    12. a[k] = a[i];
    13. k = i;
    14. }
    15. }
    16. a[k] = a[0];
    17. }
    18. void BuildMaxHeap(int a[],int len){
    19. for (int i = len/2; i > 0; i--) {//遍历所有的分支结点
    20. HeadAdjust(a,i,len);//调用函数对序列进行大根堆化
    21. }
    22. }
    23. void HeapSort(int a[],int len){
    24. BuildMaxHeap(a,len);//建立大根堆
    25. for (int i = len; i > 1; i--) {//进行n-1次处理
    26. int temp = a[1];//首尾交换
    27. a[1] = a[i];
    28. a[i] = temp;
    29. HeadAdjust(a,1,i-1);//每次首位交换后都要检查是否为大根堆
    30. }
    31. }
    32. int main(){
    33. int count,arr[10];
    34. scanf("%d",&count);//输入数组长度
    35. for (int i = 1; i <= count; ++i) {
    36. scanf("%d",&arr[i]);//输入数组
    37. }
    38. HeapSort(arr,count);//调用排序函数
    39. for (int i = 1; i <= count; ++i) {
    40. printf("%d ",arr[i]);//输出数组
    41. }
    42. return 0;
    43. }

    七、验证

    八、算法效率分析

    一个结点,每“下坠”一层,最多只需对比关键字2次。

    若树高为h,某结点在第i层,则将这个结点向下调整最多只需要“下坠” h-i层,关键字对比次数不超过2(h-i)

    建堆的时间复杂度

    总的时间复杂度和空间复杂度

    九、稳定性

    堆排序是不稳定的

    十、总结

  • 相关阅读:
    【Redis 一】Redis数据结构(String/Hash/List/Set/Sorted Set)、常用redis终端命令
    深入解析Java HashMap的Resize源码
    【iOS_锁】
    SAP MIRO发票过账报错 发出数量为0
    Python实现定时任务的八种方式
    WPF数据绑定Binding对数据的转换与效验(四)
    【LeetCode每日一题:1758. 生成交替二进制字符串的最少操作数~~~模拟+遍历+计数】
    4.docker容器编排(docker compose 与 docker swarm)
    关于电商API接口接入|接口请求重试的8种方法,你用哪种?
    minio拉取的时候报错了
  • 原文地址:https://blog.csdn.net/icbbm/article/details/133611594
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号