ZetCode

PHP 堆排序算法

最后修改于 2025 年 4 月 16 日

基本定义

算法是一种逐步解决问题或执行计算的程序。排序算法将元素按特定顺序排列。

常见的排序算法包括冒泡排序、选择排序、插入排序、归并排序、快速排序和堆排序。 它们各有不同的时间复杂度。

堆排序概述

堆排序是一种基于比较的排序算法,它使用二叉堆数据结构。 它的时间复杂度为 O(n log n),适用于所有情况。

该算法首先从输入数据构建一个最大堆。 然后它重复提取最大元素并重建堆。

堆排序实现

这是一个 PHP 中用于数值数据的基本堆排序实现

heap_sort.php
<?php

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

    // Build max heap
    for ($i = (int)($n / 2) - 1; $i >= 0; $i--) {
        heapify($arr, $n, $i);
    }

    // Extract elements one by one
    for ($i = $n - 1; $i > 0; $i--) {
        // Move current root to end
        [$arr[0], $arr[$i]] = [$arr[$i], $arr[0]];
        
        // Heapify reduced heap
        heapify($arr, $i, 0);
    }
}

function heapify(array &$arr, int $n, int $i): void {
    $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) {
        [$arr[$i], $arr[$largest]] = [$arr[$largest], $arr[$i]];
        heapify($arr, $n, $largest);
    }
}

$numbers = [12, 11, 13, 5, 6, 7];
heapSort($numbers);
print_r($numbers);

此实现首先从输入数组构建一个最大堆。 然后它重复提取最大元素并维护堆属性。

对文本数据进行排序

堆排序也可以按字母顺序对字符串进行排序。 这是一个例子

heap_sort_strings.php
<?php

function heapSortStrings(array &$arr): void {
    $n = count($arr);

    for ($i = (int)($n / 2) - 1; $i >= 0; $i--) {
        heapifyStrings($arr, $n, $i);
    }

    for ($i = $n - 1; $i > 0; $i--) {
        [$arr[0], $arr[$i]] = [$arr[$i], $arr[0]];
        heapifyStrings($arr, $i, 0);
    }
}

function heapifyStrings(array &$arr, int $n, int $i): void {
    $largest = $i;
    $left = 2 * $i + 1;
    $right = 2 * $i + 2;

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

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

    if ($largest != $i) {
        [$arr[$i], $arr[$largest]] = [$arr[$largest], $arr[$i]];
        heapifyStrings($arr, $n, $largest);
    }
}

$words = ["banana", "apple", "cherry", "date"];
heapSortStrings($words);
print_r($words);

此版本使用 strcmp 进行字符串比较。 该算法的工作方式相同,但比较的是字符串而不是数字。

降序排序

要按降序排序,我们修改堆化函数以创建最小堆而不是最大堆

heap_sort_descending.php
<?php

function heapSortDescending(array &$arr): void {
    $n = count($arr);

    for ($i = (int)($n / 2) - 1; $i >= 0; $i--) {
        heapifyDescending($arr, $n, $i);
    }

    for ($i = $n - 1; $i > 0; $i--) {
        [$arr[0], $arr[$i]] = [$arr[$i], $arr[0]];
        heapifyDescending($arr, $i, 0);
    }
}

function heapifyDescending(array &$arr, int $n, int $i): void {
    $smallest = $i;
    $left = 2 * $i + 1;
    $right = 2 * $i + 2;

    if ($left < $n && $arr[$left] < $arr[$smallest]) {
        $smallest = $left;
    }

    if ($right < $n && $arr[$right] < $arr[$smallest]) {
        $smallest = $right;
    }

    if ($smallest != $i) {
        [$arr[$i], $arr[$smallest]] = [$arr[$smallest], $arr[$i]];
        heapifyDescending($arr, $n, $smallest);
    }
}

$numbers = [12, 11, 13, 5, 6, 7];
heapSortDescending($numbers);
print_r($numbers);

此实现找到最小的元素而不是最大的元素,从而得到降序。 同样的方法也适用于字符串,通过修改比较。

堆排序与快速排序

堆排序和快速排序都是高效的排序算法,平均时间复杂度为 O(n log n)。 但是,它们具有不同的特性。

快速排序通常在实践中更快,因为它具有更好的缓存性能和更小的常数因子。 然而,堆排序在最坏情况下保证了 O(n log n) 的性能。

基准测试比较

让我们通过基准测试比较堆排序和快速排序的性能

sort_benchmark.php
<?php

function quickSort(array &$arr, int $low, int $high): void {
    if ($low < $high) {
        $pi = partition($arr, $low, $high);
        quickSort($arr, $low, $pi - 1);
        quickSort($arr, $pi + 1, $high);
    }
}

function partition(array &$arr, int $low, int $high): int {
    $pivot = $arr[$high];
    $i = $low - 1;

    for ($j = $low; $j <= $high - 1; $j++) {
        if ($arr[$j] < $pivot) {
            $i++;
            [$arr[$i], $arr[$j]] = [$arr[$j], $arr[$i]];
        }
    }
    [$arr[$i + 1], $arr[$high]] = [$arr[$high], $arr[$i + 1]];
    return $i + 1;
}

// Generate large random array
$largeArray = [];
for ($i = 0; $i < 10000; $i++) {
    $largeArray[] = rand(1, 100000);
}

// Benchmark heap sort
$heapArray = $largeArray;
$heapStart = microtime(true);
heapSort($heapArray);
$heapTime = microtime(true) - $heapStart;

// Benchmark quick sort
$quickArray = $largeArray;
$quickStart = microtime(true);
quickSort($quickArray, 0, count($quickArray) - 1);
$quickTime = microtime(true) - $quickStart;

echo "Heap sort time: " . number_format($heapTime, 6) . " seconds\n";
echo "Quick sort time: " . number_format($quickTime, 6) . " seconds\n";

此基准测试创建一个大的随机数组,并测量两种算法的排序时间。 快速排序通常在随机数据上表现更好。

何时使用堆排序

来源

维基百科上的堆排序

本教程涵盖了 PHP 堆排序算法,并提供了数值和文本数据的示例,包括升序和降序排序。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出 所有 PHP 教程