堆排序 Heap Sort
前言
- 空间复杂度
- 只是使用了一个交换用的空间,空间复杂度就是 O(1)
- 稳定性
- 不稳定的排序算法
- 是利用堆性质的一种选择排序,在堆顶选出最大值或者最小值
- 时间复杂度
- 堆排序的时间复杂度为 O(nlogn)
- 由于堆排序对原始记录的排序状态并不敏感,因此它无论最好、最坏和平均时间复杂度均为 O(nlogn)
概述
若以升序排序说明,把数组转换成最大堆积 (Max-Heap Heap) ,这是一种满足最大堆积性质 (Max-Heap Property) 的二叉树:对于除了根之外的每个结点 i , A[parent(i)] >= A[i]
重复从最大堆积取出数值最大的结点(把根结点和最后一个结点交换,把交换后的最后一个结点移出堆),并让残余的堆积维持最大堆积性质。
构建一个堆排序的三步骤
最大堆调整 (Max Heapify)
- 将堆的末端子节点作调整,使得子节点永远小于父节点
创建最大堆(Build Max Heap)
- 将堆中的所有数据重新排序
堆排序(HeapSort)
- 移除位在第一个数据的根结点,并做最大堆调整的递归运算
算法实现
origin = [30, 20, 80, 40, 50, 10, 60, 70, 90]
# 定义堆排序
def heap_sort(array):
# total 值为传入列表的长度
total = len(origin)
# 在输入的列表索引为0的位置插入一个0,方便后面计算
array.insert(0,0)
# 定义堆,进行最大堆调整
def heap_adjust(array, total, i):
while 2 * i < total: # 如果 2i<total 那么i结点一定有左子孩子,索引为 2i
lchild_index = 2 * i
max_child_index = lchild_index # 假设最大孩子索引为左子孩子索引
# 如果总结点数大于左子孩子结点,那么存在右子孩子,如果右子孩子索引对应数值
# 大于左子孩子索引数值,那么最大孩子结点索引值交换
if max_child_index < total and array[max_child_index + 1] > array[lchild_index]:
max_child_index = lchild_index + 1
# 如果最大孩子索引所对的值 大于 i 结点对应的值,交换值
if array[max_child_index] > array[i]:
array[max_child_index], array[i] = array[i], array[max_child_index]
i = max_child_index
# 否则的话,打破循环
else:
break
# 定义 创建最大堆的函数,将堆中的所有数据重新排序
def max_heap(array,total):
# 根据树的性质,做一个循环,调用 最大堆调整 来进行调整
for i in range(total//2, 0, -1):
heap_adjust(array, total, i)
# 调用 创建最大堆 的函数
max_heap(origin, total)
# 定义 内部堆排序函数,通过判断总数大小进行循环调整,并且做一个小优化
def _sort(array, total):
while total >= 1:
array[1], array[total] = array[total], array[1]
total -= 1
# 判断 当总数为 2时,剩下的两个数是否相等,相等就不用交换,打破循环
if total == 2 and array[total] >= array[total -1]:
break
# 通过循环调用最大堆调整,来进行调整
heap_adjust(array, total, 1)
return array
# 调用 内部堆排序函数
_sort(array, total)
# 返回值要把之前插入的 0 排除在外
return array[1:]
print(heap_sort(origin))
print(origin)
完整代码展示
origin = [30, 20, 80, 40, 50, 10, 60, 70, 90]
def heap_sort(array):
total = len(origin)
array.insert(0,0)
def heap_adjust(array, total, i):
while 2 * i < total:
lchild_index = 2 * i
max_child_index = lchild_index
if max_child_index < total and array[max_child_index + 1] > array[lchild_index]:
max_child_index = lchild_index + 1
if array[max_child_index] > array[i]:
array[max_child_index], array[i] = array[i], array[max_child_index]
i = max_child_index
else:
break
def max_heap(array,total):
for i in range(total//2, 0, -1):
heap_adjust(array, total, i)
max_heap(origin, total)
def _sort(array, total):
while total >= 1:
array[1], array[total] = array[total], array[1]
total -= 1
if total == 2 and array[total] >= array[total -1]:
break
heap_adjust(array, total, 1)
return array
_sort(array, total)
return array[1:]
print(heap_sort(origin))
print(origin[1:])
以上…