堆排序及其相關操作

這裏記錄下堆的相關操作。

op 1:

'''
	@ data: the heap array
	@ p   : index of parent item 
	@ n   : number of data
	@@ Swap p and it's son items, make p the largest of them
'''
def swapForMaxHeap(data, n, p):
	ls = p << 1 | 1
	rs = ls + 1
	# p has two sons or just left
	if ls < n  or rs < n:
		if rs < n:
			if data[ls] < data[rs]: ls = rs
		if data[p] < data[ls]:
			data[p], data[ls] = data[ls], data[p]
		return ls
	return -1

上面函數的功能,是將p所代表的父節點與其子節點的值進行比較,與節點值大的子節點交換節點值,使得父節點的值最大,並返回與其進行交換的子節點的索引。若無交換,則返回 -1.

op 2:

'''
	@ data: the heap array
	@ p   : index of parent item 
	@ n   : number of data
	@@ Swap p and it's son items, make p the smallest of them
'''
def swapForMinHeap(data, n, p):
	ls = p << 1 | 1
	rs = ls + 1

	# p has two sons or just left
	if ls < n  or rs < n:
		if rs < n:
			if data[ls] > data[rs]: ls = rs
		if data[p] > data[ls]:
			data[p], data[ls] = data[ls], data[p]
			return ls
	return -1

與上面的函數類似,只是取小的結點值。

op 3:

def Swap(data, n, p, ls = 0):
	
	fun = {}
	fun[0] = swapForMaxHeap
	fun[1] = swapForMinHeap
	return fun[ls](data, n, p)

將上面的兩個函數進行下封裝,參數ls表示的是堆的類型, 0 表示大根堆, 1 表示是小根堆。

op 4:

'''
	@ data : the heap array
	@ i    : the start index to be fixUp
	@ n    : the number of data
	@ ls   : if 0, it is a max heap, otherwise, min one

	@@ 
'''
def fixUp(data, i, n, ls = 0):
	if n <= 1: return
	if i <= 0 or i >= n: return

	p = (i - 1) >> 1
	while p >= 0:
		Swap(data, n, p, ls)
		p = (p - 1) >> 1

結點的上溯過程,用於插入操作,插入的時候,先將新結點的值插入到堆數組的尾部,因爲這個新的結點可能違反堆的性質,需要向上調整,直到調整到最頂端。

op 5:

def fixDown( data, i, n, ls = 0):
	if n <= 1: return
	if i < 0 or i >= n: return
	while i <= n - 1:
		index = Swap(data, n, i, ls)
		if index == -1: break
		i = index
結點的下沉過程,用於刪除和堆的建立。刪除的操作,只在堆頂進行,即刪除堆頂元素,刪除時,將堆的最後元素與堆頂進行交換,交換後,新的堆頂元素可能違反堆的性質,所以需要向下調整。

op 6:

'''
	@ data: data array that adjust to be heap
	@ n   : number of data
	@ ls  : 0-max heap, 1- min heap
'''
def buildHeap(data, n, ls = 0):
	if n <= 1: return
	for i in xrange( (n >> 1) - 1, -1, -1):
		fixDown(data, i, n, ls)

堆的建立其實不需要從0開始,也就是將數組中的元素一個個的插入到空的堆中,因爲若沒有大小堆的大小限制,給定的數組也可以視爲是一種堆,只不過是雜亂無章的堆,我們只需要對這些元素進行下調整就可以了,就是從最後一個非葉子結點開始,向下調整。

op 7:

def insert(data, new_x, ls = 0):
	data.append(new_x)
	n = len( data )
	fixUp(data, n - 1, n , ls)

這就是插入操作了,插入的時候將新元素插入到最後,然後上溯,調整爲符合堆的性質。

op 8:

def delete(data, n, ls = 0):
	if n <= 0: return
	if n == 1:
		del data[0]
		return
	data[0], data[-1] = data[-1], data[0]
	del data[-1]
	print data
	fixDown(data, 0, n - 1, ls)
	

刪除操作允許在堆頂進行,刪除後那個空缺這麼辦呢?身份最單調的就是最後一個結點,因爲其肯定不會有孩子結點,而且也不會打亂下標,所以我們用其與堆頂交換,代碼裏是爲了說明交換的意思,其實只要將最後結點的值賦值給堆頂就好了,即 data[ 0 ] = data[ -1]。然後刪除最後一個結點。從上向下調整。

op 9:

def heapSort(data, n, ls = 0):
	if n <= 1: return
	for i in xrange(n - 1, -1, -1):
		data[i], data[0] = data[0], data[i]
		fixDown(data, 0, i, ls)
	data.reverse()
	print data

這就是堆排序的排序了,以小根堆爲例,堆頂就是整個序列的最小,將其與最後的結點交換,然後調整,調整後的堆頂又是相對最小的,再交換。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章