"""
堆排序:是一种树形选择排序方法,特点:
在排序的过程中,将L[1...n]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,
在当前无序区中选择关键字最大(或最小)的元素。
堆的定义如下:
n个关键字序列L[1...n]称为堆,当且仅当该序列满足:
1、 L(i) <= L(2i) { L(i) <= L(2i+1)} 满足此公式的称为小根堆
2、 L(i) >= L(2i) { L(i) >= L(2i+1)} 满足此公式的称为大根堆
(其中1 =< i <= {n/2}向下取整 )
显然,在大根堆中,最大的元素存放在根节点中,且对其任一非根结点,它的值小于或者等于其双亲结点的值。
堆排序的思想(以大根堆为例):
堆排序的关键是构造初始堆,对初始序列建堆,就是一个反复筛选的过程。
1、首先将待排序的数组构造出一个大根堆(自下往上逐步调整为大根堆):
建堆的思路:n个结点完全的二叉树,最后一个结点是第{n/2}个结点的孩子。
对以{n/2}结点为根的子树筛选:(大根堆:若根结点的关键字小于左右子女中关键字较大者则交换),使该子树成
为堆。之后向前依此对以各结点(n/2-1 ~ 1)为根的子树进行筛选,看该结点值是否大于其左右子结点的值,若不是,
将左右子结点中较大值与之交换,交换后可能破坏下一级的堆,于是继续采用上述方法构造下一级的堆,直到以该结点
为根的子树构成堆为止。
2、取出这个大根堆的堆顶结点(最大值),与堆的最下最右的元素进行交换,把剩下的元素再构造出一个大根堆
3、重复第二步,直到这个大根堆的长度为1,此时完成排序。
"""
# Python的collections库里提供了链表结构deque,我们先使用它初始化一个无序序列:
from collections import deque
def swap_param(L, i, j):
L[i], L[j] = L[j], L[i]
return L
def heap_adjust(L, start, end):
"""
删除堆顶元素时,先将最后一个元素与堆顶元素交换,由于此时破坏了堆的性质,需要
对此时根结点进行向下调整操作。
:param L:
:param start:
:param end:
:return:
"""
# 对以[n/2]结点为根的子树筛选,temp 暂存根节点start
temp = L[start]
i = start
j = 2 * i
# 沿着key(关键字)较大的子结点向下筛选
while j <= end:
# 保证 j 取到左右子树中关键字较大的值
if (j < end) and (L[j] < L[j + 1]):
j += 1
if temp < L[j]:
L[i] = L[j]
i = j
j = 2 * i
else:
# 筛选结束:temp>=L[j]:说明根结点的关键字最大。
break
L[i] = temp
def adjust_up(L, k):
"""
对堆进行插入操作,先将新结点放在堆的末端,对新结点执行向上调整。
:param L:
:param k: 向上调整的结点,也为堆的元素个数
:return:
"""
temp = L[k]
i = k // 2
while i > 0 and L[i] < L[0]:
L[k] = L[i]
k = i
i = k //2
L[k] = temp
def heap_sort(L):
"""
因为引入了一个辅助空间,所以使L_length = len(L) - 1
第一个循环做的事情是把序列调整为一个大根堆(heap_adjust函数)
第二个循环是把堆顶元素和堆末尾的元素交换(swap_param函数),然后把剩下的元素调整为一个大根堆(heap_adjust函数)
:param L:
:return:
"""
L_length = len(L) - 1
first_sort_count = L_length // 2
# 从i = [n/2]-1 ,反复调整堆
for i in range(first_sort_count):
heap_adjust(L, first_sort_count - i, L_length)
for i in range(L_length - 1):
L = swap_param(L, 1, L_length - i)
heap_adjust(L, 1, L_length - i - 1)
return [L[i] for i in range(1, len(L))]
if __name__ == '__main__':
L = deque([50, 16, 30, 10, 60, 90, 2, 80, 70])
L.appendleft(0)
print(heap_sort(L))