算法导论学习笔记之堆排序

一、堆概念

(二叉)堆是一个数组,它可以看成一个近似的完全二叉树,树上的每个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左向右填充的

它有这样的性质:

对于给定一个结点的下标 i ,很容易计算得到它的父节点、左孩子、右孩子的下标:

父节点下标:i >> 1

左孩子下标:i << 1

右孩子下标:( i << 1 ) + 1

二叉堆分为最大堆和最小堆:

在最大堆中,除了根以外的结点 i 都要满足:A[ i >> 1] >= A[ i ],而在最小堆中,则满足 A[ i >> 1] <= A[ i ]

二、堆排序(使用最大堆)

堆排序需要下列基本例程:

调整堆:调整堆为最大堆

构建堆:创建一个最大堆

堆排序:排序

调整堆例程,它输入为一个数组A和一个下标 i ,在调用调整堆例程时,它会将以 i 为根的堆调整为最大堆

调整堆(A,i)
	l = left(i)	// i << 1
	r = right(i)	//(i << 1) + 1
	if l <= A.heap-size && A[ l ] > A[ i ]
		largest = l
	else
		largest = i
	if r <= A.heap-size && A[ r ] > A[ largest ]
		largest = r
	if i != largest
		交换A[ i ] 和 A[ largest ]
		调整堆(A,largest)

构建堆例程以数组 A 作为输入,该例程可以将A[ 1..n ] 转换为最大堆,可以证明:子数组A[ n/2 + 1 .. n ]中的元素都是树的叶子结点。

构建堆(A)
	A.heap-size = A.length
	for i = A.length/2 .. 1 step = -1	//叶子结点可以看成只有一个元素的最大堆,不需要调整
		调整堆(A,i)

堆排序算法:

利用最大堆的上述2个例程,可以轻松实现堆排序算法:

·拿掉最大堆根结点,此节点为序列中的最大值,作为一次输出

·将堆尾结点换到根结点处,形成新堆,新堆长度减 1

·调整新堆为最大堆

堆排序(A)
	构建堆(A)
	for i = A.length .. 2 step = -1
		交换A[ 1 ]与A[ i ]
		--A.heap-size	//堆长度减 1
		调整堆(A,1)

堆排序算法的时间复杂度被证明为拥有对数复杂度O(nlgn)



你可能感兴趣的:(算法)