堆排序

排序算法 平均时间复杂度 空间复杂度 稳定性
冒泡排序 $O(n^2)$ $O(1)$ 稳定
选择排序 $O(n^2)$ $O(1)$ 不稳定
插入排序 $O(n^2)$ $O(1)$ 稳定
希尔排序 $O(n\log^2 n)$ $O(1)$ 不稳定
归并排序 $O(n\log^2 n)$ $O(n)$ 稳定
快速排序 $O(n\log n)$ $O(\log n)$ 不稳定
堆排序 $O(n\log n)$ $O(1)$ 不稳定
计数排序 $O(n+k)$ $O(k)$ 稳定
基数排序 $O(n\times k)$   稳定
桶排序 $O(n)$ $O(m)$ 稳定

堆排序使用一种被称为堆的数据结构进行排序。

(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树。树上的每一个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且从左向右填充。二叉堆可以分为两种形式:大顶堆和小顶堆在这里插入图片描述 大顶堆:每个结点的值都大于或等于其左右孩子结点的值,堆中最大的元素存放在根节点。 小顶堆:每个结点的值都小于或等于其左右孩子结点的值,堆中最小的元素存放在根节点。

由于堆是一个数组,对于大顶堆它的实际存储为: 在这里插入图片描述 给定堆中的一结点下标为 i,则其左孩子和右孩子对应下标分别为 2i+1 和 2i+2,若数组下标自 1 开始,则其左孩子和右孩子对应下标分别为 2i 和 2i+1。

堆排序算法(以大顶堆为例)

将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余 n-1 个元素重新构造成一个堆,这样会得到 n 个元素的次小值。如此反复执行,便能得到一个有序序列了

维护堆性质的函数

整个排序算法都建立在待排序列为大顶堆的基础上,而在根结点与末尾元素进行交换时会破坏大顶堆结构,需要有对大顶堆进行维护的函数。

在该函数中给出根节点下标 root,根据堆的性质得到其左右孩子结点下标,选出三个结点的最大值,并将最大值下标赋给 max。若 root 为最大结点,以 root 为根节点的子树已经是最大堆,程序结束。否则,最大值是 root 的某个孩子结点,交换 max 结点同 root 结点的值。由于 root 结点的一个孩子结点值发生改变,以该孩子结点为根的子树可能违反最大堆性质,递归调用函数。

def max_heapify(arr, root):
    max_, left, right = root, 2 * root + 1, 2 * root + 2
    # 全局变量 arr_len
    if left < arr_len and arr[left] > arr[max_]:
        max_ = left
    if right < arr_len and arr[right] > arr[max_]:
        max_ = right
    
    if max_ != root:
        arr[root], arr[max_] = arr[max_], arr[root]
        max_heapify(arr, max_)

建堆函数

想要进行堆排序,首先需要将初始序列变成大顶堆 我们可以用自底向上的方法利用函数 max_heapify() 将一个初始序列变成大顶堆

def build_max_heap(arr):
    # 叶子节点无需维护堆性质
    # 不需遍历整个数组
    for i in range(len(arr) // 2,-1,-1):
        max_heapify(arr,i)

排序函数

将大顶堆根节点与末尾元素进行交换,此时末尾就为最大值。然后将剩余 n-1 个元素重新构造成一个堆,这样会得到 n 个元素的次小值。如此反复执行,便能得到一个有序序列了

def heap_sort(arr):
    global arr_len
    arr_len = len(arr)
    if arr_len < 2:
        return arr
    
    build_max_heap(arr)
    for i in range(len(arr) - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]
        arr_len -= 1
        max_heapify(arr, 0)

知识来源

«算法导论»第6章堆排序 图片直接从这位大大这拿图并参考https://www.cnblogs.com/chengxiao/p/6129630.html *** 本博客文章仅供博主学习交流,博主才疏学浅,语言表达能力有限,对知识的理解、编写代码能力都有很多不足,希望各路大神多多包涵,多加指点。