第6章《堆排序》:堆排序,python实现

  • 定义:堆是一个数组,它可以看成一个近似的完全二叉树,树上的每个节点对应数组中的一个元素,除了最底层外,该数是完全充满的,而且是从左向右充满,如下图所示:
    在这里插入图片描述
  • 基本性质:给定一个节点的下标 i i i,则它的父节点 ⌊ i / 2 ⌋ \lfloor i/2 \rfloor i/2,左孩子: 2 i 2i 2i,右孩子: 2 i + 1 2i+1 2i+1
  • 最大堆 A [ p a r e n t ( i ) ] ≥ A [ i ] A[parent(i)] \ge A[i] A[parent(i)]A[i],在任一子树中,该子树所包含的所有节点的值都不大于该子树根节点值,堆中的最大元素存放在根节点中
  • 最小堆 A [ p a r e n t ( i ) ] ≤ A [ i ] A[parent(i)] \le A[i] A[parent(i)]A[i],在任一子树中,该子树所包含的所有节点的值都不小于该子树根节点值,堆中的最小元素存放在根节点中

堆的性质

最大堆保证其根节点 A [ i ] ≥ A [ l e f t ( i ) ] A[i] \ge A[left(i)] A[i]A[left(i)] A [ i ] ≥ A [ r i g h t ( i ) ] A[i] \ge A[right(i)] A[i]A[right(i)],下图为在第 i = 2 i=2 i=2的节点,保证最大堆性质移动操作步骤:
在这里插入图片描述
代码实现如下:


# 维持最大堆的性质
def max_heapify(A, i, size):
	# 节点i的左孩子, 由于python 索引是从0开始,不是从1开始,所以左 2*i --> 2*i+1   右 2*i+1 --> 2*i+2
	l = 2*i+1
	# 节点i的右孩子
	r = 2*i + 2
	#size = len(A)
	size = size
	if l<size and A[l]>A[i]:
		largest = l
	else:
		largest = i
	if r<size and A[r]>A[largest]:
		largest = r
	if largest!=i:
		temp = A[i]
		A[i] = A[largest]
		A[largest] = temp
		# 以largest为根节点的子树,可能又违背最大堆性质,所以需要继续递归调用
		max_heapify(A, largest, size)

建堆

用自底向上的方法,利用上述维持堆的性质,把长度为 n n n的数组 A A A转换成最大堆,根据堆的性质, ⌊ n / 2 ⌋ + 1 , . . , n \lfloor n/2 \rfloor +1,..,n n/2+1,..,n是叶子节点,所以,只需要对其他非叶子节点调用max_heapify,图过程如下:
在这里插入图片描述
代码块:

#建堆,自顶向下方法,把一个大小为n的数组A,转换为最大堆
def build_max_heap(A):
	size = len(A)
	mid = int(size/2) - 1
	#从堆的性质得出 A[mid+1..size]都是树的叶节点,所以只需要对其他节点调用max_heapify,保证最大堆的性质就可
	for i in range(mid,-1,-1):
		max_heapify(A,i, size)
	return A

堆排序算法

因为数组中最大元素总在第一个元素根节点 A [ 1 ] A[1] A[1]中,通过把它与 A [ n ] A[n] A[n]交换,同时从堆中去掉节点 n n n,新交换的节点可能不能满足最大堆性质,所以每次需要重新调用max_heapify函数,堆排序算法复杂度为 O ( n l g n ) O(nlgn) O(nlgn),整个流程代码如下:

# -*-coding:utf8 -*-
import sys


# 维持最大堆的性质
def max_heapify(A, i, size):
	# 节点i的左孩子, 由于python 索引是从0开始,不是从1开始,所以左 2*i --> 2*i+1   右 2*i+1 --> 2*i+2
	l = 2*i+1
	# 节点i的右孩子
	r = 2*i + 2
	#size = len(A)
	size = size
	if l<size and A[l]>A[i]:
		largest = l
	else:
		largest = i
	if r<size and A[r]>A[largest]:
		largest = r
	if largest!=i:
		temp = A[i]
		A[i] = A[largest]
		A[largest] = temp
		# 以largest为根节点的子树,可能又违背最大堆性质,所以需要继续递归调用
		max_heapify(A, largest, size)


#建堆,自顶向下方法,把一个大小为n的数组A,转换为最大堆
def build_max_heap(A):
	size = len(A)
	mid = int(size/2) - 1
	#从堆的性质得出 A[mid+1..size]都是树的叶节点,所以只需要对其他节点调用max_heapify,保证最大堆的性质就可
	for i in range(mid,-1,-1):
		max_heapify(A,i, size)
	return A

def heap_sort(A):
	#建堆
	build_max_heap(A)
	print(A)
	length = len(A)
	#最大元素总在根节点A[0],通过与最后一个节点交换A[length-1],新的节点需要维持最大堆性质,同时每次去掉交换后的最后一个节点
	for i in range(length-1,0,-1):
		# chage A[0] with A[i]
		temp = A[i]
		A[i] = A[0]
		A[0] = temp
		max_heapify(A,0, i)
	return A
if __name__=='__main__':
	A = [4,1,3,2,16,9,10,14,8,7]
	print(A)
	A = heap_sort(A)
	print(A)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
堆排序是一种排序算法,它基于二叉堆的数据结构。堆排序的时间复杂度为O(nlogn),空间复杂度为O(1)。 以下是使用Python实现堆排序的代码: ``` def heapify(arr, n, i): largest = i l = 2 * i + 1 # left child r = 2 * i + 2 # right child if l < n and arr[i] < arr[l]: largest = l if r < n and arr[largest] < arr[r]: largest = r if largest != i: arr[i],arr[largest] = arr[largest],arr[i] heapify(arr, n, largest) def heapSort(arr): n = len(arr) for i in range(n, -1, -1): heapify(arr, n, i) for i in range(n-1, 0, -1): arr[i], arr[0] = arr[0], arr[i] heapify(arr, i, 0) arr = [12, 11, 13, 5, 6, 7] heapSort(arr) n = len(arr) print("Sorted array is") for i in range(n): print("%d" %arr[i]), ``` 在上面的程序中, `heapify()`函数用于维护堆的性质,该函数接受一个数组、一个数组的长度和一个索引值作为输入,其中i是当前的根节点。函数使用largest变量存储具有最大值的索引。然后可以通过比较左子节点和右子节点来确定largest的值。当largest变量的值不等于i时,表示最大或最小值被修改,此时需要在子树中递归堆排列以保持堆结构的性质。 在` heapSort()`函数中,对于给定输入数组,首先通过遍历所有非叶子节点来构建一个最大堆 ,其余所有的节点都满足最大堆的性质。 然后对于每个元素,将它移至堆的底部,逐步进行堆排列以保证根节点是堆的最大值。 在完成第一个元素后,我们可以只对余下的元素执行相同的操作,从而获得排序的数组。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值