作者:小灰

来自:程序员小灰(ID:chengxuyuanxiaohui)

在上一篇漫画中,小灰介绍了 二叉堆 这样一种强大的数据结构:

漫画:什么是二叉堆?(修正版)

那么,这个二叉堆怎样来使用呢?我们这一期将会详细讲述。

让我们回顾一下二叉堆和最大堆的特性:

1.二叉堆本质上是一种完全二叉树

2.最大堆的堆顶是整个堆中的最大元素

当我们删除一个最大堆的堆顶(并不是完全删除,而是替换到最后面),经过自我调节,第二大的元素就会被交换上来,成为最大堆的新堆顶。

正如上图所示,当我们删除值为10的堆顶节点,经过调节,值为9的新节点就会顶替上来;当我们删除值为9的堆顶节点,经过调节,值为8的新节点就会顶替上来.......

由于二叉堆的这个特性,我们每一次删除旧堆顶,调整后的新堆顶都是大小仅次于旧堆顶的节点。那么我们只要反复删除堆顶,反复调节二叉堆,所得到的集合就成为了一个有序集合,过程如下:

删除节点9,节点8成为新堆顶:

删除节点8,节点7成为新堆顶:

删除节点7,节点6成为新堆顶:

删除节点6,节点5成为新堆顶:

删除节点5,节点4成为新堆顶:

删除节点4,节点3成为新堆顶:

删除节点3,节点2成为新堆顶:

到此为止,我们原本的最大堆已经变成了一个从小到大的有序集合。之前说过二叉堆实际存储在数组当中,数组中的元素排列如下:

由此,我们可以归纳出堆排序算法的步骤:

1. 把无序数组构建成二叉堆。

2. 循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。

public class HeapSort {

  1. /**

  2. * 下沉调整

  3. * @param array     待调整的堆

  4. * @param parentIndex    要下沉的父节点

  5. * @param parentIndex    堆的有效大小

  6. */

  7. public static void downAdjust(int[] array, int parentIndex, int length) {

  8.    // temp保存父节点值,用于最后的赋值

  9.    int temp = array[parentIndex];

  10.    int childIndex = 2 * parentIndex + 1;

  11.    while (childIndex < length) {

  12.        // 如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子

  13.        if (childIndex + 1 < length && array[childIndex + 1] > array[childIndex]) {

  14.            childIndex++;

  15.        }

  16.        // 如果父节点小于任何一个孩子的值,直接跳出

  17.        if (temp >= array[childIndex])

  18.            break;

  19.        //无需真正交换,单向赋值即可

  20.        array[parentIndex] = array[childIndex];

  21.        parentIndex = childIndex;

  22.        childIndex = 2 * childIndex + 1;

  23.    }

  24.    array[parentIndex] = temp;

  25. }


  26. /**

  27. * 堆排序

  28. * @param array     待调整的堆

  29. */

  30. public static void heapSort(int[] array) {

  31.    // 1.把无序数组构建成二叉堆。

       for (int i = (array.length-2)/
    2; i >= 0; i--) {

  32.        downAdjust(array, i, array.length);

  33.    }

  34.    System.out.println(Arrays.toString(array));

  35.    // 2.循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。

  36.    for (int i = array.length - 1; i > 0; i--) {

  37.        // 最后一个元素和第一元素进行交换

  38.        int temp = array[i];

  39.        array[i] = array[0];

  40.        array[0] = temp;

  41.        // 下沉调整最大堆

  42.        downAdjust(array, 0, i);

  43.    }

  44. }


  45. public static void main(String[] args) {

  46.    int[] arr = new int[] {1,3,2,6,5,7,8,9,10,0};

  47.    heapSort(arr);

  48.    System.out.println(Arrays.toString(arr));

  49. }

}

二叉堆的节点下沉调整(downAdjust 方法)是堆排序算法的基础,这个调节操作本身的时间复杂度是多少呢?

假设二叉堆总共有n个元素,那么下沉调整的最坏时间复杂度就等同于二叉堆的高度,也就是O(logn)

我们再来回顾一下堆排序算法的步骤:

1. 把无序数组构建成二叉堆。

2. 循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。

第一步,把无序数组构建成二叉堆,需要进行n/2次循环。每次循环调用一次 downAdjust 方法,所以第一步的计算规模是  n/2 * logn,时间复杂度 O(nlogn)

第二步,需要进行n-1次循环。每次循环调用一次 downAdjust 方法,所以第二步的计算规模是 (n-1) * logn ,时间复杂度 O(nlogn)

两个步骤是并列关系,所以整体的时间复杂度同样是 O(nlogn)

—————END—————

长按订阅同类文章

一起搬砖的点个赞

今晚,咱们就聊聊堆排序吧!相关推荐

  1. 十大经典排序算法详解(三)-堆排序,计数排序,桶排序,基数排序

    养成习惯,先赞后看!!! 你的点赞与关注真的对我非常有帮助.如果可以的话,动动手指,一键三连吧!!! 十大经典排序算法-堆排序,计数排序,桶排序,基数排序 前言 这是十大经典排序算法详解的最后一篇了. ...

  2. 【经济学_04】晨读:保险的实质 特效药 医疗膨胀 保险的发明

    文章目录 晨读:保险的实质 情景 认知 本质 Q1:那么保险是资产还是负债呢? Q2:富人也喜欢保险? 对于企业来说保险的好处 无时无刻都在接触保险 为什么说,越穷的人越需要配保险 保险特点 特点1: ...

  3. 知乎16万赞:“你对空姐提过最奇怪的要求是什么?”回答暴露文化水平

    01 前段时间,刷到一个很有意思的知乎问题:"你对空姐提出过最奇怪的要求是什么?" 其中有个回答获赞最高,有16.5万人点了赞同. 答主"牛布尼茨"说,他爷爷曾 ...

  4. TikTok 还有机会吗?

    阅读本文大概需要 1.29 分钟. 在开年的时候,我们星球跟 TikTok 官方合作,举办了一次挑战活动,其实去年也举办过类似的,由我们组局,然后 TikTok 官方人员带队.主要考虑到星球里面不少人 ...

  5. 【今晚7点】:圆桌PI回归 继续聊聊开源的故事

    点击上方"LiveVideoStack"关注我们 圆桌PI,是LiveVideoStack公开课的形式之一,我们会约上几位专家进行线上的虚拟圆桌讨论,分享观点,探讨热点话题,回答听 ...

  6. 今晚8点和 Conflux 张元杰聊聊,在中国做 Web3 的机会在哪里?

    关于 Web3,你可能看到了这样的现象和论断: 受限于强监管,在国内做 Web3 完全没有机会,只能去海外.一度我们可以看到一个壮观的场景,国内 Web2 大厂的精英们,纷纷奔赴海外,作为国人的首选新 ...

  7. 清华大学计算机吴教授开讲啦,开讲啦!吴建平院士今晚十点半CCTV-1聊聊互联网二三事儿...

    原标题:开讲啦!吴建平院士今晚十点半CCTV-1聊聊互联网二三事儿 1 月 27 日 周 六 今晚十点半 中国工程院院士.清华大学计算机科学与技术系主任.CERNET专家委员会主任吴建平教授做客中央电 ...

  8. 【今晚七点】:对话快手张亮——聊聊音视频出海

    点击上方"LiveVideoStack"关注我们 自疫情以来,人们的生活.工作.出行都受到了一定限制,这也使得大家对线上社交及办公的需求不断提升,推动音视频行业快速发展的同时也带来 ...

  9. 聊聊Service Mesh:linkerd

    [编者的话]随着企业逐渐将传统的单体应用向微服务或云原生应用的转变,虽然微服务或者云原生应用能给企业带来更多的好处,但也会带来一些具有挑战的问题,如怎么管理从单体应用转向微服务所带来的服务间通讯的复杂 ...

最新文章

  1. 践行科技向善,腾讯Light 把光引向厦门
  2. python比较数据库表今天跟前一天数据增量,Python 生产环境Mysql数据库增量备份脚本...
  3. antd 侧边栏如何自适应高度
  4. 自动构建工具Grunt
  5. 第一行代码学习笔记第八章——运用手机多媒体
  6. CSS 如何设置垂直居中
  7. 知乎高赞:这个开挂神器简直了!
  8. java while等待 yeild_Java中run(), start(), join(), wait(), yield(), sleep()的使用
  9. Visual Studio 2008 Service Pack 1 - BETA发布
  10. MACOS,应用签名后就崩溃?
  11. crackme用来测试程序设计人员的逆向工程技能的小程序。
  12. 系统篇: fstab 文件详解
  13. 绝地反击 我的战胜贫困的经历01 转载 整理
  14. KVM虚拟化的概述和部署
  15. 免费好用的征集工具 | 玩转穿搭征集、好物征集、攻略征集
  16. 花了10分钟,终于弄懂了特征值和特征向量到底有什么意义
  17. [案例4-2]饲养员喂养动物
  18. javascript原型、原型链神图
  19. 全球及中国犬淋巴瘤治疗行业研究及十四五规划分析报告
  20. PANSS 阳性与阴性症状量表

热门文章

  1. 二分图HK算法[数论+二分图最大独立集]:Lightoj1356
  2. codeforces数学1600day6[CodeForces - 1029C多区间交+枚举,CodeForces 992C[数学公式推导],CodeForces 992B[质因数分解+暴力枚举]]
  3. html盒子宽高,css盒子模型之宽度和高度
  4. 抢红包算法 c语言,红包分配算法,抢红包算法
  5. POJ2932Coneology(计算几何、平面扫描)
  6. 并查集(压缩路径+按秩排序)
  7. java字节流6_JavaIO流之字节流
  8. 在目前大数据时代下,怎么能成为一名合格的数据分析师
  9. mysql找安装路经,更改密码
  10. java中父类与子类的关系以及使用