数据结构 - 堆排序(Python 实现)
堆
-
完全二叉树
假设二叉树的深度为 h h h,除第 h h h 层外,其它各层 1 ~ ( h − 1 ) 1~(h-1) 1~(h−1) 的节点数都达到最大个数,第 h h h 层所有的节点都 连续 集中在最左边,这就是完全二叉树。
完全二叉树可用数组表示。
-
堆
堆分为大顶堆(节点元素值大于左右子节点元素值)和小顶堆(节点元素值小于左右子节点元素值)。
-
堆排序
堆排序属于选择排序,不稳定排序,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
在排序后,存储在数组中的元素成有序序列。
降序使用小顶堆(每次都将第 i i i 小元素置于数组倒数第 i i i 位置);
升序使用大顶堆(每次都将第 i i i 大元素置于数组倒数第 i i i 位置)。
相关详细理论可参阅 堆排序理论介绍
Python 代码实现
def max_heap(arr, length):
"""
每一遍的最大堆排序 max_heap 都会选出最大的元素,并置于堆顶
:param arr: 传入待排数组的指针
:param length: 当前需要排序的数组长度
:return: None
"""
# 每次从最后一个非叶子结点开始
start = length // 2 - 1
# 因为是从最后一个结点开始,所以以后每次只需将目标根元素索引减一
# 即相当于从右向左,从下至上遍历了所有非叶子结点
for root in range(start, -1, -1):
# 当前非叶子结点(下称:根节点)的左子节点与右子节点的索引
left = root * 2 + 1
right = left + 1
# 比较左子节点与右子节点,将二者中的最大值与根节点比较
if right < length:
temp = left if arr[left] > arr[right] else right
else:
temp = left
# 将最大值与当前根节点交换
if arr[root] < arr[temp]:
arr[root], arr[temp] = arr[temp], arr[root]
def sort_heap(arr):
length = len(arr)
# 对待排数组构建初始堆,此时最大值已经处于堆顶
max_heap(arr, length)
# 对长度len-1的待排数组进行堆性质维护
for l in range(len(arr)-1, -1, -1):
# 之所以长度len-1,是因为每次都已经将最大值置于序列尾部
# 已经处于尾部的最大值不要在进行排序
arr[l], arr[0] = arr[0], arr[l]
# 对长度len-1的待排序列进行堆排序
max_heap(arr, l)
print(arr)
if __name__ == '__main__':
from random import randint
arr = [randint(0, 25) for _ in range(5)]
print("init:", arr)
sort_heap(arr)
print("end:", arr)