首页 > 代码库 > 堆排序

堆排序

与归并排序一样,但不同于插入排序,堆排序的时间复杂度为O(nlgn)。与插入排序一样,但不同于归并排序,堆排序具有空间原始性,即排序过程中只需要常数个额外的元素空间来存储临时数据。

1、堆是一个数组,它可以看成一个近似的完全二叉树,树上的每个节点对应着数组中的每个元素。对于一个给定下标为 i 的元素  ,可以很容易的计算出它的父节点,左孩子和右孩子的下标。

技术分享   

技术分享        

技术分享

 

2、堆又分为两种,最大堆和最小堆。最大堆的性质:除了根节点外,其余节点要满足条件A[parent(i)]≥A[i]。最小堆的性质:除了根节点外,其余节点要满足条件A[parent(i)]≤A[i]。

 

3、下面是基于最大堆的堆排序过程。

  基本过程:

    MAX-HEAPIFY过程:用于维护最大堆的性质 即A[parent(i)]≥A[i]。时间复杂度为Ο(lgn)。

    BUILD-MAX-HEAP过程:功能是将一个无序数组构造为一个最大堆的过程。时间复杂度为Ο(n)。

    HEAPSORT过程:其功能是对一个数组进行原址排序。时间复杂度为Ο(nlgn)。

 

4、MAX-HEAPIFY过程,维护最大堆性质

  在调用MAX-HEAPIFY(A,i)过程的时候,假设前提根节点为left(i)和right(i)的二叉树都是最大堆,但这时A[i]可能小于其孩子left(i)和right(i),这就违背了最大堆的性质。通过调用MAX-HEAPIFY过程,可以使得根节点为i的二叉树为最大堆。

  伪代码如下图:

 

MAX-HEAPITY(A,i)
1    l = left(i)
2    r = right(i)
3    if(l <= A.heap-size && A[i] < A[l])
4        largest = l
5    else largest = i
6    if(r <= A.heap-size && A[largest] <A[r])
7        largest = r
8    if(largest != i)
9        exchange A[largest] with A[i]
10       MAX-HEAPITY(A,largest)

   

  下图展示了MAX-HEAPIFY过程。

技术分享

  上图中,以i的孩子left(i)和right(i)为根节点的二叉树都是最大堆,但是A[i]小于left[i]和right[i],所以A[i]为根节点的二叉树不是最大堆,调用MAX-HEAPIFY过程,将数组转换为一个最大堆。

   对于一颗以i为根节点,大小为n的堆,MAX-HEAPIFY过程的时间代价为T(n),其中包括:伪代码1-9行时间代价为θ(1),假设8行条件成立,则会调用10行的递归过程。因为每个孩子的子树大小至多为2n?3(最坏情况发生在最底层恰好为半满的时候),所以10行时间代价小于等于T(2n/3)。因此MAX-HEAPIFY过程的时间代价 T(n)<=T(2n/3)+θ(1)。利用递归式主方法,上面递归式的解为T(n)=O(lgn)。一个含有n个元素的堆,堆高度h=θ(lgn),所以对一个树高度为h的节点来说,MAX-HEAPIFY过程的时间复杂度为O(h)。

 

5、BUILD-MAX-HEAP过程,建堆

  建堆的过程是将一个大小为n=A.length的数组A[1,2,...,n]转换为最大堆的过程。从底层第一个有孩子的节点开始,自低向上的逐个节点调用MAX-HEAPIFY过程,直到最顶层根节点为止。下标为技术分享的元素都是树的叶节点,过程BUILD-MAX-HEAP对树中的其他节点都调用一次MAX-HEAPIFY。下面是BUILD-MAX-HEAP过程的伪代码:

 

BUILD-MAX-HEAP(A)
1    A.heap-size = A.length
2    for i = floor(A.length/2) downto 1  //floor为向下取整
3        MAX-HEAPIFY(A,i)

 

下图为BUILD-MAX-HEAP过程的例子

技术分享

  BUILD-MAX-HEAP过程的时间代价为O(n)。

  每次调用MAX-HEAPIFY(A,i)过程的时间代价为O(lgn),BUILD-MAX-HEAP过程中,round(A.length/2) downto 1总共有O(n)次调用MAX-HEAPIFY(A,i)过程。所以直观上BUILD-MAX-HEAP过程总的时间复杂度为O(nlgn)。

  但MAX-HEAPIFY(A,i)过程的时间代价与高度h有关系,并且大多数节点的高度都很小,所以可以计算出更为精确的上界。利用如下性质:1、含有n个元素的堆的高度为floor(lgn) (注:floor为向下取整);2、对于任一包含n个元素的堆中,至多有ceil(n/2h+1) (注:ceil为向上取整)个高度为h的节点。

  BUILD-MAX-HEAP过程的时间代价可以表示为:技术分享,又有技术分享,所以有BUILD-MAX-HEAP过程的时间复杂度为:技术分享

 

6、HEAPSORT过程(堆排序算法)

 

HEAPSORT(A)
1    BUILD-MAX-HEAP(A)
2    for i = A.length dowto 2
3        exchange A[i] with A[1]
4        A.heap-size = A.heap-size-1
5        MAX-HEAPIFY(A,1)

  

  首先将数组A转换为一个最大堆,此时数组A中的最大元素肯定位于堆的根节点A[1],通过根节点A[1]与节点A[n]的交换,可以将A[1]放到正确的位置。这时候,通过 A.heap-size = A.heap-size-1 操作将节点A[n]从堆中去掉,剩余的节点中,A[1]的两个孩子均为最大堆的根节点,但是A[1]可以小于它的孩子,因此调用MAX-HEAPIFY(A,1)过程,使得A[1,2,...,n-1]转换为最大堆。下图为HEAPSORT的一个例子。

  堆排序的时间复杂度为O(nlgn)。BUILD-MAX-HEAP(A)过程的时间代价为O(n),n-1次调用MAX-HEAPIFY的时间代价为O(nlgn),所以堆排序的时间复杂度为O(nlgn)。

  技术分享

堆排序