第3课_希尔排序的基本思想
热度🔥:11 免费课程
授课语音
希尔排序的基本思想
1. 简介
希尔排序(Shell Sort)是由美国数学家Donald Shell在1959年提出的一种排序算法。希尔排序是对插入排序的优化。插入排序在数据量较小时表现良好,但在数据量较大时效率低下,因为它的时间复杂度是O(n²)。希尔排序通过引入间隔的概念,使得插入排序在排序过程中跳跃性地比较和交换元素,从而减少了元素的移动次数,大大提高了排序效率。
2. 基本思想
希尔排序的核心思想是将待排序数组分成若干个子数组,对每个子数组进行插入排序。初始时,子数组的划分是基于一个增量序列来决定的。随着算法的进行,增量逐渐减小,最终增量为1时,整个数组变成一个有序序列。希尔排序的关键在于如何选择增量序列,这直接影响到排序的效率。
希尔排序的排序过程大致如下:
- 选择一个增量序列,将数组分为若干个子数组。
- 对每个子数组分别进行插入排序。
- 重复步骤1和步骤2,直到增量为1,此时再对整个数组进行一次插入排序。
3. 例子
假设我们有一个数组[5, 2, 9, 1, 5, 6]
,使用希尔排序进行排序。假设我们使用增量序列为[3, 1]
,那么排序过程如下:
第一次增量为3,我们将数组分为3个子数组:
- 第一个子数组:
[5, 1]
- 第二个子数组:
[2, 5]
- 第三个子数组:
[9, 6]
对这3个子数组分别进行插入排序:
- 对
[5, 1]
进行插入排序,得到[1, 5]
- 对
[2, 5]
进行插入排序,得到[2, 5]
- 对
[9, 6]
进行插入排序,得到[6, 9]
此时,数组变成
[1, 2, 6, 5, 5, 9]
。- 第一个子数组:
第二次增量为1,我们将数组分成1个子数组,也就是整个数组,然后进行一次插入排序。最终得到排序后的数组
[1, 2, 5, 5, 6, 9]
。
4. Java代码实现
public class ShellSort {
// 希尔排序函数
public static void shellSort(int[] arr) {
int n = arr.length;
// 初始增量为数组长度的一半,每次将增量减半
for (int gap = n / 2; gap > 0; gap /= 2) {
// 进行插入排序
for (int i = gap; i < n; i++) {
// 保存当前元素
int temp = arr[i];
int j = i;
// 通过插入排序插入到合适的位置
while (j >= gap && arr[j - gap] > temp) {
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
}
}
}
// 测试函数
public static void main(String[] args) {
int[] arr = {5, 2, 9, 1, 5, 6};
System.out.println("排序前:");
printArray(arr);
// 执行希尔排序
shellSort(arr);
System.out.println("排序后:");
printArray(arr);
}
// 打印数组
public static void printArray(int[] arr) {
for (int i : arr) {
System.out.print(i + " ");
}
System.out.println();
}
}
5. 代码解析
- 在代码中,我们首先计算出初始的增量
gap
,它等于数组的长度除以2。 - 然后,我们使用一个外循环控制增量的变化,每次将
gap
减半,直到gap
为1时停止。 - 内部的插入排序部分通过
temp
保存当前元素,将其插入到合适的位置,通过gap
来进行“跳跃式”插入。
6. 时间复杂度
希尔排序的时间复杂度并不是固定的,取决于增量序列的选择。若使用最简单的增量序列(如1, 2, 3, ..., n),那么希尔排序的时间复杂度接近于O(n²),这和直接使用插入排序差不多。但如果选择了合适的增量序列,时间复杂度可以降到O(n^1.3),甚至更低。
对于常见的增量序列,时间复杂度如下:
- 最坏情况下:O(n²)
- 最好情况下:O(n log n)
- 平均情况下:O(n^1.3)
7. 空间复杂度
希尔排序是一种原地排序算法,因此它的空间复杂度是O(1)。
8. 优缺点
优点:
- 希尔排序是对插入排序的优化,对于大多数数据集来说,希尔排序表现优于插入排序。
- 它在处理部分有序的数组时非常高效,能够显著提高排序速度。
缺点:
- 希尔排序的时间复杂度不确定,取决于增量序列。
- 最坏情况下,希尔排序的时间复杂度依然可能达到O(n²)。
希尔排序是一种有效的排序算法,适用于处理中等规模的数组。它在实际应用中,因其简单且较高效,常常作为插入排序的改进版本使用。