我想了想,仍是结合书中的每一句话来解释一下他们的前因后果吧,首先堆排序的时间复杂度是O(nlgn),也就是咱们所说的大O时间复杂度。为何说是nlgn的时间复杂度呢?首先咱们须要知道max-heapfify的时间复杂度是lgn,也就是咱们一般所说的log2n,由于数据结构当中的堆本质上还二叉树。那么这个n从哪里来呢?每一次Max-heapify都是一个调整堆成为最大堆的过程,每一次只能调整一个元素,由于堆中有n个元素,因此咱们要调整n次才能把全部元素调整到正确的地方,这很像冒泡排序,可是实际上这并非冒泡排序。稍后会跟你们详细说一下。api
那么说到堆排序,咱们首先应该去思考一下,什么是堆?既然堆是二叉树,那么堆确定会知足二叉树相关的性质。另外这里所说的堆,并非Java的JVM所说的堆,这里所说的堆,仅仅限于数据结构。若是用数组来进行表示的话,须要注意一点,堆中的有效元素,并非整个数组,它有可能会小于这个数组的元素个数,那么为何会是这样的呢?具体能够参考这篇文章。数组
堆当中有3个比较重要的概念,一个是根节点,一个是左子树,一个是右子树。而堆通常分为最大堆和最小堆,通常来讲:堆排序所说的,都是最大堆,而最小堆通常用于构造优先队列。那么下面咱们仍是拿最大堆来讲一下,最大堆,顾名思义,根节点是最大的,它应该比左子树和右子树的节点值都要大,这不只仅说是比它的孩子大,并且这个操做是递归的。也就是说没有任何一个节点可以比根节点更大。那么左子树和右子树之间有没有什么关系呢?若是用数组来表示的话,我以为只是一个物理存储位置之间的关系。二叉树的遍历相关的知识点你们能够去百度上搜一下,永远记住这么一点,二叉树的完美之处是在于它利用了计算机的原理,也就是二进制移位,这样能够大大提升效率,这就是为何计算机只有2叉树,没有三叉树,四叉树的缘由了。在最大堆当中,根节点的值永远大于或等于子节点的值。数据结构
这一节来看看怎么维护堆的正确性。先来看一段伪代码吧,下面这段代码是不能独立的,它依赖于i的位置。也就是说,i实际上是根节点(咱们所认为的),其实它在树当中不必定是根节点,还有一点想跟你们阐述的是:根节点是相对的,相对于它的子树来讲,只要是非叶子节点,均可以认为是根节点。而下面的代码,实际上只是根据最大堆的性质,把大的往上移而已;注意最后一句话,它是一个递归,也就是说,它的做用是把大的节点尽量地往根上面靠拢,直到不能再交换位置为止。递归的终止条件就是largets==i.
spa
固然也就是建立一个堆了,本质上来讲,建堆其实也就是一个不断调整元素的过程,使其达到最大堆,由于若是一个数组是未排序的,若是想按照堆排序来进行排序,那么就要利用下面的代码。注意一下,为何是a.lenght/2呢?仍是回到以前提到的二叉堆的性质,MAX-HEAPIFY是向下进行遍历的,而A.lenght/2刚好是叶子节点的父节点。这样作的好处,就是能够把每个节点都放到正确的位置上,就像这样来解释:曾祖父,爷爷,父亲,你,儿子,孙子。这几个的顺序是乱的,假设先从儿子开始,儿子发现他的位置比孙子小(也就是儿子是子节点,孙子是父节点),而后交换顺序,第一次循环结束,第二次发现你竟然比儿子的顺序要小,而后交换你和儿子的顺序,继续查找,发现孙子竟然排在你的前面了,赶忙交换位置,而后你和儿子和孙子都在正确的位置上了。这么不停循环,直到曾祖父,你们最后都在了正确的位置上,因此建堆的时间复杂度是外层循环n和内层MAX-HEAPIFY的一个乘积。.net