算法设计与分析——堆排序

本文介绍了堆排序算法的思想,从二叉树的角度阐述了堆的定义,并详细解释了如何构造和调整堆。堆排序的时间复杂度为O(nlogn),不需要额外空间,适合学习二叉树和排序算法。此外,提供了C语言实现的代码示例。
摘要由CSDN通过智能技术生成

前言

一个高效的排序算法,对整个计算机领域的贡献都是极大的。在我看来,堆排序算法就是这样一种高效的排序算法,它本身的设计就是非常巧妙的。

一、算法思想分析

要理解堆排序,首先就得理解,什么是堆?在《算法设计与分析基础》中有如下定义:
堆的定义——《算法设计与分析基础》
简而言之,所谓堆,就是一棵二叉树(如果大家不理解二叉树的概念的,可参考百度百科——二叉树,等我以后写了二叉树分析的博客再附上我自己的,嘿嘿。),一棵父节点元素一定大于等于子节点元素完全二叉树(以上不是水字数,只是附上我的理解罢了)。
堆的定义——举例
如上图,看第二个,首先其根本不是一棵完全二叉树,那么也就不可能称作是堆了。看第三个,包含元素5的节点,其子节点中,存在一个包含元素6的节点,显然不满足堆的特性,也不是堆。综上分析,只有第一棵树可以称作是堆
堆的一些重要属性
而堆排序呢,正是利用了堆的这些特性,故而称作堆排序(怎么听起来有点拗口呢?不管了,就是这个意思就对了)。对于二叉树,我们通常用数组来进行存储,稍微特殊一点的是,我们存储位置的起始下标是1,不是0。那么,这个时候我们就可以得出父节点和子节点的数组下标之间的关系了。
堆中父母节点和子节点的关系
那么,给出我们一个数组,我们如何来构造一个堆呢?我们正是利用的以上父子节点之间下标的关系来构造一个堆。
在这里,我们自底向上来构造堆(自顶向下的方法其实差不多,大家有兴趣的可以研究研究)。

  • 1.首先找到最后一个父(母)节点,由上我们可知,最后一个父节点的下标是数组长度除2后向取整
  • 2.找到一个父节点后,将该父节点与其两个子节点进行比较,左孩子和右孩子的下标我们同样可以找到,在两次比较中,如果子节点的元素比父节点的元素大,那么我们将两个节点的元素交换。两次比较完之后呢?这个时候我们就结束了么?如果没有元素交换,那么本次比较就结束了,但如果发生了元素交换,那么就没有结束。我们要完成一次堆的构造,就必须保证这个二叉树满足堆的所有特性,当此时并没有完全满足。因为我们上述操作不过是将父元素与其子元素比较,但我们并不能保证当前被交换的子节点它就不是一个父节点(想象一下,一个节点是不是可能既是子节点又是父节点?),那么根据堆的特性,我们就要将此时被交换的子节点看作是一个父节点,来重复我们前面的操作(也就是继续和其子节点比较),直到这个节点他大于他的所有子节点(亦或是没有子节点了),那么本次交换就到此结束了(这里讲解篇幅略长,如果实在看不太懂,可以先看下面的算法实现,然后回来看)。
  • 3.这个时候,我们刚才找到的那个父节点的所有交换就已经完成了,我们就要开始去走它的上一个节点(自底向上就是这么来的),也就是下标减一(说白了,我们就是在遍历所有的父节点并将这些父节点和他们的子节点比较大小),这里的父节点我们要指明一下,这里的父节点是从n/2向下取整开始一个个递减所有父节点。
  • 4.重复上述第二步和第三步操作,直至我们遍历到第一个节点并比较完毕。
  • 5.第四步完成之后,我们就完成了一次堆构造了,此时我们的根节点一定是一个元素值最大的节点,并且当前一定是一个堆。那么这个时候,关键的一步来了。将根节点元素与当前数组最后一个元素交换,当前数组的最后一个元素非常之关键,那么我们交换后,当前数组的最后一个元素就是当前数组中最大的元素了。
  • 6.将当前数组的长度减一,从第一步开始继续重复操作。直至数组长度为1,算法结束。

堆排

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值