希尔排序是一种基于插入排序的排序算法,通过先将数组分组,对每组进行局部排序,再逐渐减少组间隔,最终实现整体排序。它由 Donald Shell 在 1959 年提出,是插入排序的一种更高效的改进版本,特别适用于大规模数组排序。
目录
算法思路
希尔排序的核心在于使用间隔(gap)的概念,将待排序数组分割成若干个子数组,然后对各个子数组进行插入排序。随着算法的进行,逐步缩小间隔,直到间隔为 1,此时整个数组基本有序,最后一次插入排序即可完成全局排序。
- 初始间隔:通常选用数组长度的一半作为初始间隔。
- 分组排序:将数组按照当前间隔分成若干子数组,每个子数组进行独立的插入排序。
- 逐步缩小间隔:更新间隔值,一般取 gap = gap/2,重复上述步骤。
- 最终排序:当间隔减小到 1 时,整个数组已经近乎有序,此时进行一次标准插入排序即可完成排序。
PHP 代码实现
下面给出一个使用 PHP 实现希尔排序的示例代码:
<?php
function shellSort(array &$arr) {
$n = count($arr);
// 初始间隔设为数组长度的一半
for ($gap = floor($n / 2); $gap > 0; $gap = floor($gap / 2)) {
// 对每个分组执行插入排序
for ($i = $gap; $i < $n; $i++) {
$temp = $arr[$i];
$j = $i;
// 向前比较,插入到合适位置
while ($j >= $gap && $arr[$j - $gap] > $temp) {
$arr[$j] = $arr[$j - $gap];
$j -= $gap;
}
$arr[$j] = $temp;
}
}
return $arr;
}
// 测试
$data = [64, 34, 25, 12, 22, 11, 90];
echo "排序前: " . implode(", ", $data) . "\n";
shellSort($data);
echo "排序后: " . implode(", ", $data);
?>
输出:
排序前: 64, 34, 25, 12, 22, 11, 90
排序后: 11, 12, 22, 25, 34, 64, 90
时间复杂度分析
- 最坏情况:O(n²)
当数据排序极为不利时,希尔排序的比较和交换次数可能接近 O(n²)。 - 平均情况:介于 O(n²) 与 O(n log n) 之间
实际性能依赖于间隔序列的选择,不同的间隔序列会影响排序效率。 - 最佳情况:O(n)
如果数组已经接近有序,希尔排序可以非常快速完成排序。
空间复杂度:O(1)(原地排序,无需额外存储空间)
适用场景与优势
- 数据量中等:对于中等规模的数据集,希尔排序常常比简单的插入排序和冒泡排序更高效。
- 初步排序:在其他高效排序算法(如快速排序)之前进行预排序,能提升整体效率。
- 内存有限:由于希尔排序是原地排序,所以在内存受限的情况下表现出色。
- 可扩展性:不同的间隔序列选择可以根据实际情况进行优化,提升排序性能。
练习题
- 实现希尔排序的递归版本:尝试用递归思路重写希尔排序代码。
- 间隔序列优化:尝试使用 Knuth 序列(
gap = gap * 3 + 1
)或其他间隔序列改进希尔排序,并比较其与传统 gap/2 方式的性能。 - 排序稳定性分析:讨论希尔排序的稳定性问题,并通过代码验证不同输入数据下排序是否稳定。
- 多维数组排序:扩展希尔排序,使其能够对二维数组按指定列进行排序。
相关链接
🔗 GeeksforGeeks – Shell Sort
🔗 Algorithm Visualizer – Shell Sort
🔗 Wikipedia – Shell Sort
参考资料
- 《算法导论》—— Thomas H. Cormen 等
- 《数据结构与算法分析》—— Mark Allen Weiss
- GeeksforGeeks – Sorting Algorithms
希望这篇关于希尔排序的详细介绍和代码练习对你有所帮助!如果有其他算法需要讲解,欢迎继续提问。
发表回复