目录

  1. 什么是堆排序
  2. 堆排序的原理
  3. 堆排序的步骤
  4. 堆排序的实现
  5. 堆排序的时间复杂度
  6. 应用场景
  7. 参考资料
  8. 出站链接

1. 什么是堆排序

堆排序(Heap Sort)是一种基于比较的排序算法,它利用了堆这一数据结构的特性。堆是一种完全二叉树,并且满足堆的性质:

  • 最大堆:每个节点的值都不小于其子节点的值。
  • 最小堆:每个节点的值都不大于其子节点的值。

堆排序将待排序的数组构建成堆结构,并通过反复调整堆,最终得到一个排序好的数组。堆排序是一个不稳定的排序算法,它的时间复杂度为 O(nlog⁡n)O(n \log n)。


2. 堆排序的原理

堆排序的基本思路如下:

  1. 构建最大堆:将待排序数组构建成一个最大堆,使得堆顶元素(最大元素)为整个数组的最大值。
  2. 交换堆顶元素与最后一个元素:将堆顶元素与堆的最后一个元素交换位置。
  3. 调整堆:每次交换后,堆的结构会被破坏,因此需要对堆顶元素进行下沉操作,使其重新符合堆的性质。
  4. 重复步骤 2 和 3:继续进行交换和调整,直到堆的大小为 1。

3. 堆排序的步骤

堆排序的具体步骤如下:

  1. 构建最大堆:从最后一个非叶子节点开始,依次对每个节点执行下沉操作,将数组调整成最大堆。
  2. 交换堆顶元素和最后一个元素:每次将最大元素移到数组的末尾。
  3. 重新调整堆:在交换后的数组中,堆的根节点被破坏,需要通过下沉操作恢复堆的性质。
  4. 继续交换和调整:重复步骤 2 和 3,直到堆只剩一个元素。

4. 堆排序的实现

PHP 代码实现

function heapify(&$arr, $n, $i) {
    $largest = $i;
    $left = 2 * $i + 1;
    $right = 2 * $i + 2;

    if ($left < $n && $arr[$left] > $arr[$largest]) {
        $largest = $left;
    }
    if ($right < $n && $arr[$right] > $arr[$largest]) {
        $largest = $right;
    }

    if ($largest != $i) {
        // 交换
        list($arr[$i], $arr[$largest]) = [$arr[$largest], $arr[$i]];
        heapify($arr, $n, $largest);
    }
}

function heapSort(&$arr) {
    $n = count($arr);

    // 构建最大堆
    for ($i = floor($n / 2) - 1; $i >= 0; $i--) {
        heapify($arr, $n, $i);
    }

    // 排序过程
    for ($i = $n - 1; $i > 0; $i--) {
        // 将堆顶元素(最大元素)与当前元素交换
        list($arr[0], $arr[$i]) = [$arr[$i], $arr[0]];
        // 调整堆
        heapify($arr, $i, 0);
    }
}

// 测试代码
$arr = [12, 11, 13, 5, 6, 7];
heapSort($arr);
print_r($arr);

输出结果

Array
(
    [0] => 5
    [1] => 6
    [2] => 7
    [3] => 11
    [4] => 12
    [5] => 13
)


Python 代码实现

def heapify(arr, n, i):
    largest = i
    left = 2 * i + 1
    right = 2 * i + 2

    if left < n and arr[left] > arr[largest]:
        largest = left
    if right < n and arr[right] > arr[largest]:
        largest = right

    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]  # 交换
        heapify(arr, n, largest)

def heap_sort(arr):
    n = len(arr)

    # 构建最大堆
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)

    # 排序过程
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]  # 交换堆顶元素
        heapify(arr, i, 0)

# 测试代码
arr = [12, 11, 13, 5, 6, 7]
heap_sort(arr)
print(arr)

输出结果

[5, 6, 7, 11, 12, 13]


5. 堆排序的时间复杂度

  • 时间复杂度
    • 构建最大堆:需要对每个非叶子节点执行一次下沉操作,时间复杂度为 O(n)O(n)。
    • 排序过程:每次交换堆顶元素后,需要重新调整堆,调整堆的时间复杂度为 O(log⁡n)O(\log n),需要执行 n−1n-1 次交换操作。因此,排序过程的时间复杂度为 O(nlog⁡n)O(n \log n)。
    所以,堆排序的总时间复杂度为 O(n \log n)
  • 空间复杂度:堆排序是一种原地排序算法,它只需要常数级别的额外空间,因此空间复杂度为 O(1)

6. 应用场景

  • 优先队列:堆排序的最大堆和最小堆性质常用于实现优先队列。
  • 实时数据流:堆排序在动态数据中可以保持有序性,特别适用于流数据的实时排序。
  • 排序算法选择:堆排序不依赖于数据的初始顺序,适用于大数据的排序,尤其当内存受限时,堆排序由于其 O(nlog⁡n)O(n \log n) 的时间复杂度表现优异。

7. 参考资料

  1. 《算法导论》第 6 章 – 堆排序
  2. LeetCode 题解:https://leetcode.cn/problems/kth-largest-element-in-an-array/
  3. GeeksForGeeks 堆排序:https://www.geeksforgeeks.org/heap-sort/

8. 出站链接