堆排序时间复杂度的理解

来源:互联网 发布:火影忍者晓戒指淘宝 编辑:程序博客网 时间:2024/05/17 06:17

 

堆排序

 这里不再赘述堆的定义 和堆排序的讲解,详见海子的博客http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html,里面图示已经很清楚了,这里首先对该博客对我的启发表示感谢。

 

难点:1. 对堆的理解:

                           从堆的定义可以看出,堆有两个性质:i. 完全二叉树(即按二叉树逐层从左到右排列数据,这样便于所以某个节点的父节点或者子节点);ii. 大顶堆(或小顶堆)(即任何父节点大于(或者小于)左子节点和右子节点中的最大值(或最小值))

                 另外,对于所有元素中根节点最大的堆称为最大堆或者大根堆(同理也有最小堆或者小根堆)。

           2. 构造最大堆:从最后一个非叶子节点开始把每一对二叉树元素(一个父节点和其子节点)进行构造堆操作(即如果左子节点和有子节点中的最大值比父节点更大,就与父节点交换以保证父节点最大,并且对以该子节点为根的二叉树元素继续递归上述操作以保证交换后的二叉树仍然是堆(即满足第二个条件)),一直往前进行到顶层的二叉树元素为止。  最终得到的堆即为最大堆。   以上操作复杂度为O(n),大概需进行n/2 * 2 = n次比较和n/2次交换。

                         关于最大堆,有一个性质:即任意改变最大堆的根节点(这里主要是减小根节点的值,不然几乎不用操作)后对最大堆的根节点进行一次构造堆操作,得到的堆仍然是最大堆。这里我没有给出证明,但可以理解的是,由于上述构造堆操作是递归进行的,因此,较大的数(或者说第二大的数)绝不会藏在堆的下方,在递归操作下肯定会往上顶。     后来想想似乎不用证明,因为第二大数肯定是根节点的子节点,进行一次交换即可保证堆是最大堆。

              上述构造堆操作的算法复杂度是O(log2(n))的理解:  假设该操作的时间是T(n),则最大的T(n) = T(2/3 n) + O(1),这里的O(1)指的是根节点及其左右子节点的操作,它肯定是有限的(最多两次比较一次交换),如果有交换需要对以某个子节点为根的堆重复上述操作,由于堆是完全二叉树,因此该新堆的数量不会超过2/3 n,所以得到了上式。     在《算法导论》的4.1节有一个主定理的证明,即当满足T(n) = aT(n/b) + f(n)  满足一定条件时,可得T(n)的时间复杂度为O(log2(n))    (其实书中说是log n,我的理解就是log2(n))

            3.  有了以上基础,就很好理解堆排序的时间复杂度了。

               堆排序算法为:构造最大堆,从而得到最大的元素,将最大的元素与最后一个元素交换(即取出最大的元素),然后对根节点为首的除最后一个元素之外的n-1个元素进行一次构造堆操作,由之前讨论了的性质可以知道,该一次操作后得到的堆仍为最大堆,故可以继续将根节点与第n-1个节点交换,取出第二大元素……重复上述操作直到依次取出第n-1大元素即完成了排序。

                 时间复杂度为 T(n) <=  O(n)  + (n - 1)*O(log2(n)),即等于第一次构造最大堆操作 加上  后面n-1次构造堆操作   其实由于n的减小,后面的O(log2(n))中的n也会减小,所以这里用小于等于号 。最后得到的T(n) =O(nlog2(n)).

原创粉丝点击