PHP 归并排序算法
最后修改于 2025 年 4 月 16 日
基本定义
算法 是一种逐步解决问题或执行计算的程序。在编程中,算法被实现为函数或方法。
排序 是指将数据按特定顺序排列,通常是升序或降序。有效的排序对于优化其他算法(如搜索操作)至关重要。
常见的排序算法包括
- 归并排序
- 快速排序
- 气泡排序
- 插入排序
- 选择排序
- 堆排序
归并排序概述
归并排序是一种分治算法,它递归地将输入数组分成两半,对它们进行排序,然后合并已排序的两半。
它在所有情况下都具有 O(n log n) 的时间复杂度,使其对于大型数据集非常有效。它是一种稳定的排序算法,需要 O(n) 的额外空间。
基本归并排序实现
以下是升序排列数字数据的基本归并排序实现。
merge_sort_basic.php
<?php
function mergeSort(array $array): array {
if (count($array) <= 1) {
return $array;
}
$mid = (int) (count($array) / 2);
$left = array_slice($array, 0, $mid);
$right = array_slice($array, $mid);
$left = mergeSort($left);
$right = mergeSort($right);
return merge($left, $right);
}
function merge(array $left, array $right): array {
$result = [];
$i = $j = 0;
while ($i < count($left) && $j < count($right)) {
if ($left[$i] <= $right[$j]) {
$result[] = $left[$i++];
} else {
$result[] = $right[$j++];
}
}
while ($i < count($left)) {
$result[] = $left[$i++];
}
while ($j < count($right)) {
$result[] = $right[$j++];
}
return $result;
}
$numbers = [34, 7, 23, 32, 5, 62];
$sorted = mergeSort($numbers);
print_r($sorted);
此实现递归地分割数组,直到每个子数组只有一个元素,然后按排序顺序将它们合并回原数组。
对文本数据进行排序
归并排序也可以按字母顺序对字符串进行排序。这是一个包含文本数据的示例。
merge_sort_text.php
<?php
function mergeSortText(array $array): array {
if (count($array) <= 1) {
return $array;
}
$mid = (int) (count($array) / 2);
$left = array_slice($array, 0, $mid);
$right = array_slice($array, $mid);
$left = mergeSortText($left);
$right = mergeSortText($right);
return mergeText($left, $right);
}
function mergeText(array $left, array $right): array {
$result = [];
$i = $j = 0;
while ($i < count($left) && $j < count($right)) {
if (strcmp($left[$i], $right[$j]) <= 0) {
$result[] = $left[$i++];
} else {
$result[] = $right[$j++];
}
}
while ($i < count($left)) {
$result[] = $left[$i++];
}
while ($j < count($right)) {
$result[] = $right[$j++];
}
return $result;
}
$names = ["John", "Alice", "Bob", "Zoe", "Charlie"];
$sortedNames = mergeSortText($names);
print_r($sortedNames);
此版本使用 strcmp 比较字符串。输出将是按字母顺序排列的名称。
降序排序
要以降序排序,我们只需在合并函数中反转比较。
merge_sort_desc.php
<?php
function mergeSortDesc(array $array): array {
if (count($array) <= 1) {
return $array;
}
$mid = (int) (count($array) / 2);
$left = array_slice($array, 0, $mid);
$right = array_slice($array, $mid);
$left = mergeSortDesc($left);
$right = mergeSortDesc($right);
return mergeDesc($left, $right);
}
function mergeDesc(array $left, array $right): array {
$result = [];
$i = $j = 0;
while ($i < count($left) && $j < count($right)) {
if ($left[$i] >= $right[$j]) {
$result[] = $left[$i++];
} else {
$result[] = $right[$j++];
}
}
while ($i < count($left)) {
$result[] = $left[$i++];
}
while ($j < count($right)) {
$result[] = $right[$j++];
}
return $result;
}
$numbers = [34, 7, 23, 32, 5, 62];
$sortedDesc = mergeSortDesc($numbers);
print_r($sortedDesc);
唯一的更改是合并函数中的比较运算符,它现在检查大于或等于而不是小于或等于。
带有回调的通用归并排序
我们可以通过添加比较回调使我们的归并排序更灵活。
merge_sort_generic.php
<?php
function mergeSortGeneric(array $array, callable $compare): array {
if (count($array) <= 1) {
return $array;
}
$mid = (int) (count($array) / 2);
$left = array_slice($array, 0, $mid);
$right = array_slice($array, $mid);
$left = mergeSortGeneric($left, $compare);
$right = mergeSortGeneric($right, $compare);
return mergeGeneric($left, $right, $compare);
}
function mergeGeneric(array $left, array $right, callable $compare): array {
$result = [];
$i = $j = 0;
while ($i < count($left) && $j < count($right)) {
if ($compare($left[$i], $right[$j]) <= 0) {
$result[] = $left[$i++];
} else {
$result[] = $right[$j++];
}
}
while ($i < count($left)) {
$result[] = $left[$i++];
}
while ($j < count($right)) {
$result[] = $right[$j++];
}
return $result;
}
// Ascending sort
$ascCompare = fn($a, $b) => $a <=> $b;
$numbers = [34, 7, 23, 32, 5, 62];
$sortedAsc = mergeSortGeneric($numbers, $ascCompare);
print_r($sortedAsc);
// Descending sort
$descCompare = fn($a, $b) => $b <=> $a;
$sortedDesc = mergeSortGeneric($numbers, $descCompare);
print_r($sortedDesc);
此版本接受一个比较函数,使其适用于任何数据类型和排序顺序。太空船运算符 (<=>) 简化了比较逻辑。
归并排序与快速排序基准测试
让我们比较一下归并排序和快速排序在大型数据集上的性能。
sort_benchmark.php
<?php
function quickSort(array $array): array {
if (count($array) <= 1) {
return $array;
}
$pivot = $array[0];
$left = $right = [];
for ($i = 1; $i < count($array); $i++) {
if ($array[$i] < $pivot) {
$left[] = $array[$i];
} else {
$right[] = $array[$i];
}
}
return array_merge(quickSort($left), [$pivot], quickSort($right));
}
function generateRandomArray(int $size): array {
$array = range(1, $size);
shuffle($array);
return $array;
}
$largeArray = generateRandomArray(10000);
// Merge sort benchmark
$start = microtime(true);
$mergeSorted = mergeSort($largeArray);
$mergeTime = microtime(true) - $start;
// Quick sort benchmark
$start = microtime(true);
$quickSorted = quickSort($largeArray);
$quickTime = microtime(true) - $start;
echo "Merge Sort time: " . number_format($mergeTime, 6) . " seconds\n";
echo "Quick Sort time: " . number_format($quickTime, 6) . " seconds\n";
两种算法的平均时间复杂度都为 O(n log n),但快速排序通常在实践中更快,因为它具有更好的缓存性能和更少的内存使用。但是,归并排序是稳定的,并保证 O(n log n) 的性能。
何时使用归并排序
- 需要稳定性: 当相等元素必须保留顺序时
- 外部排序: 当数据不适合内存时
- 链表: 适用于顺序访问数据
- 可预测的性能: 当最坏情况很重要时
来源
本教程介绍了 PHP 中的归并排序算法,并提供了不同数据类型和排序顺序的示例,以及性能比较。
作者
列出 所有 PHP 教程。