堆排序(Heap Sort)是利用堆这种数据结构而设计的一种排序算法,是一种选择排序。python
堆是具备如下性质的彻底二叉树:每一个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每一个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。git
堆排序思路为: 将一个无序序列调整为一个堆,就能找出序列中的最大值(或最小值),而后将找出的这个元素与末尾元素交换,这样有序序列元素就增长一个,无序序列元素就减小一个,对新的无序序列重复操做,从而实现排序。github
构造初始堆。将给定无序序列构形成一个大顶堆(通常升序采用大顶堆,降序采用小顶堆);算法
将堆顶元素与末尾元素进行交换,使末尾元素最大。而后继续调整堆,再将堆顶元素与末尾元素交换,获得第二大元素;数组
从新调整结构,使其知足堆定义,而后继续交换堆顶元素与当前末尾元素;数据结构
如此反复进行交换、重建、交换,直到整个序列有序。dom
# heap_sort 代码实现
def build(arr:List[int], root, end):
while True:
child = 2 * root + 1 # 左子节点的位置
if child > end: # 若左子节点超过了最后一个节点,则终止循环
break
if (child + 1 <= end) and (arr[child + 1] > arr[child]): # 若右子节点在最后一个节点以前,而且右子节点比左子节点大,则咱们的孩子指针移到右子节点上
child += 1
if arr[child] > arr[root]: # 若最大的孩子节点大于根节点,则交换二者顺序,而且将根节点指针,移到这个孩子节点上
arr[child], arr[root] = arr[root], arr[child]
root = child
else:
break
def heap_sort(arr:List[int]):
n = len(arr)
first_root = n // 2 - 1 # 确认最深最后的那个根节点的位置
for root in range(first_root, -1, -1): # 由后向前遍历全部的根节点,建堆并进行调整
build(arr, root, n - 1)
for end in range(n - 1, 0, -1): # 调整完成后,将堆顶的根节点与堆内最后一个元素调换位置,此时为数组中最大的元素,而后从新调整堆,将最大的元素冒到堆顶。依次重复上述操做
arr[0], arr[end] = arr[end], arr[0]
build(arr, 0, end - 1)
复制代码
# 测试数据
if __name__ == '__main__':
import random
random.seed(54)
arr = [random.randint(0,100) for _ in range(10)]
print("原始数据:", arr)
heap_sort(arr)
print("堆排序结果:", arr)
复制代码
# 输出结果
原始数据: [17, 56, 71, 38, 61, 62, 48, 28, 57, 42]
堆排序结果: [17, 28, 38, 42, 48, 56, 57, 61, 62, 71]
复制代码
时间复杂度函数
在每次重建时,随着堆的容量的减少,层数会降低,函数时间复杂度会变化。重建堆一共须要n-1次循环,每次循环的比较次数为,则相加为:测试
因此堆排序时间复杂度为。动画
空间复杂度
空间复杂度就是在交换元素时那个临时变量所占的内存空间,因此堆排序空间复杂度为
稳定性
堆排序在交换数据的时候,是比较父结点和子节点之间的数据,因此,即使是存在两个数值相等的兄弟节点,它们的相对顺序在排序也可能发生变化。所以,堆排序是不稳定的。
综合评价
时间复杂度(平均) | 时间复杂度(最好) | 时间复杂度(最坏) | 空间复杂度 | 排序方式 | 稳定性 |
---|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
in-place | 不稳定 |
我的博客网站:www.bling2.cn/
Github地址:github.com/lb971216008…
知乎专栏:zhuanlan.zhihu.com/Use-Python-…
小专栏:xiaozhuanlan.com/Use-Python-…
博客园:www.cnblogs.com/Use-Python-…