堆排序 python
最近由于需要参加面试的原因,重温了下排序算法,先把最后研究的堆排序python版本列出来,看了下python-data-structure-cn中对于树和堆的介绍,从网上也搜索了一些资料,把个人觉得比较好理解的整理出来。
堆看起来很像一棵树,但是当我们实现它时,我们只使用一个单一的列表作为内部表示。
二叉堆有两个常见的变体:最小堆(其中最小的键总是在前面)和最大堆(其中最大的键值总是在前面)
有这些特性后就可以进行排序操作,以最大堆为例
1、最大堆的根节点总是最大,我们只要将根节点跟列表的最后一个元素交换,最后一个就是列表中最大的,完成了一个排序,
2、第一步操作后,最后一个元素可以不考虑,只需要考虑heap_size-1这个堆,做了一次交换后,heap_size-1这个堆已经不符合最大堆的特性,需要max_heap函数完成最大堆的重建
3、重建完成后再循环继续第一步知道完成。
排序的前提是这个列表是一个堆,build_heap很关键,当然主要的工作还是在max_heap中完成,跟重建heap不同的是,重建总是从root节点开始,而最初一次堆的build则是从最后一个有子节点的节点开始,逐步到root节点,完成整个堆的构建。
def max_heap(alist, heap_size, adjust_pos):
left_child = adjust_pos * 2 + 1
right_child = adjust_pos * 2 + 2
large_pos = adjust_pos
#保证子节点存在的情况,将large_pos指向左右子节点中较大的一个。
if left_child < heap_size and alist[left_child] > alist[large_pos]:
large_pos = left_child
if right_child < heap_size and alist[right_child] > alist[large_pos]:
large_pos = right_child
#存在子节点大于父节点则进行交换,并递归完成后续所有子树的重建
if large_pos != adjust_pos:
alist[adjust_pos], alist[large_pos] = alist[large_pos], alist[adjust_pos]
max_heap(alist, heap_size, large_pos)
def build_heap(alist):
last_parent = len(alist) // 2
# 从最后一个有叶子节点的节点开始,遍历到根节点,把每个子树最大的节点往上移动,完成heap
for i in range(last_parent-1, -1, -1):
max_heap(alist, len(alist), i)
def sort_heap(alist):
build_heap(alist)
for i in range(len(alist)-1, -1, -1):
alist[0], alist[i] = alist[i], alist[0]
max_heap(alist, i, 0)
alist = [33, 22, 11, 55, 30, 32, 35, 88, 89, 22]
blist = [88, 77, 66, 55, 44, 33, 22, 11, 8, 7]
sort_heap(blist)
sort_heap(alist)
print(alist)
print(blist)