堆排序-以小根堆为例


前言

刷力扣题,遇到堆排序,考研完后就没接触数据结构,忘的差不多了,现在重现拾起来。


一、什么是堆

     堆,这个词很形象,谷堆、雪堆等,是一个底下宽上面细的金字塔。在数据结构中就是每一层的数都比上层的数大(或小)(这个说法并不太严格,下文会具体说明),按层级排列。下面将以小根堆(就是下层比上层的数大)进行记录说明。

    在了解堆之前,需要对二叉树有简单的了解,下面作简单的介绍:二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点。(具体概念请读者自行搜索了解)由于堆是一个完全二叉树,所以在此对完全二叉树也作简单介绍:满二叉树是树中每层节点都饱满的二叉树,如图:
在这里插入图片描述
(参见百度百科)
相对满二叉树,完全二叉树的定义没那么严苛,完全二叉树的最后一层可以不满,但是必须是挨个排序的,见下图:
在这里插入图片描述
(这是完全二叉树)
在这里插入图片描述

(这个不是完全二叉树,3的左子树还没排就直接排了右子树。)

好,说了这些概念,该进入正题了。小根堆是满足如下条件的完全二叉树:
其中任一非终端节点的数据值均不大于其左子节点和右子节点的值(大根堆定义类似)。这里需要注意的是,同层的结点数值并没有大小排序。
在这里插入图片描述

二、堆排序过程

1.创建堆

创建堆的思想相对简单,总体来说就是将完全二叉树调整成堆,具体做法如下:

    ① 从i=⌊n/2⌋节点开始该调整节点的子树是否满足根节点不大于左右子节点,若不满足,则进行调整,直至该节点的左右子树都不小于它,或者该节点成为叶子节点。其中n为节点总数。
    ②继续对剩余节点都进行调整,直到第一个节点也调整完毕。
(至于为什么要从i=⌊n/2⌋开始调整,请读者自行思考,同时也欢迎留言讨论。)

下面借用罗福强等的《数据结构(Java语言描述)》中图进行示例:

在这里插入图片描述
第一个调整点是i=⌊10/2⌋(5),发现5号节点只有左子树且左子树值大于该节点的值,因此无需调整。
当小根堆调整完毕后,最顶上的节点就是值最小的节点了。下面进行堆排序过程。

2.堆排序

推排序的思想也较为简单,可以将其拆分为两个步骤,第一取根节点(最顶上的节点),第二重新调整新完全二叉树至小根堆。下面对调整过程作描述:

    根节点被取出后,将最右边的叶子节点(最后一个节点)放到根节点位置进行补充,并调整(调整过程与“创建堆”的步骤①相同)新的完全二叉树。由于除了根节点,其他节点都是符合小根堆规则的,因此只需调整它即可。(若对此感到怀疑,可以手动调整一遍。)下面还是以罗福强等的《数据结构(Java语言描述)》书中图作为示例:
在这里插入图片描述


总结

    本文主要对堆的创建和排序过程的思想作了简单描述。具体实现,读者可以先自行尝试实现,再查阅其他资料书籍进行对比。若文中描述有误,还请指正,感激不尽。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值