《Java 实现希尔排序:原理剖析与代码详解》
目录
一、引言
二、希尔排序原理
三、代码分析
1. 代码整体结构
2. main方法
3. sort方法(希尔排序核心逻辑)
四、测试结果
一、引言
在排序算法的大家族中,希尔排序是一种改进的插入排序算法,它通过将原始数据分成多个子序列进行预排序,然后逐渐缩小子序列的间隔,最终对整个序列进行常规的插入排序,从而在一定程度上提高了排序的效率。在这篇博客中,我们将深入解析一段用 Java 实现希尔排序的代码,帮助大家透彻理解希尔排序的原理以及代码的具体实现细节。
二、希尔排序原理
希尔排序的基本思想基于插入排序,但它引入了一个间隔序列(也称为增量序列)的概念,使得排序过程不再是逐个元素地进行比较和插入,而是先对相隔一定间隔的元素进行比较和插入操作,随着排序的进行,间隔逐渐缩小,直到最后间隔为 1,此时就相当于进行了一次普通的插入排序。
具体来说,希尔排序的步骤如下:
- 首先选择一个合适的间隔序列,常见的如希尔本人提出的序列(
n/2, n/4, n/8, …, 1
,其中n
为数组长度)。在每一轮排序中,根据当前的间隔将数组分成多个子序列。 - 对于每个子序列,按照插入排序的方式进行排序,即比较子序列中相邻元素(这里的相邻是指间隔为当前所选间隔的元素),如果顺序不对则进行交换。
- 完成一轮排序后,缩小间隔,再次按照上述步骤对新的子序列进行排序,直到间隔缩小到 1,此时整个数组就完成了排序。
三、代码分析
1. 代码整体结构
以下是我们要详细分析的 Java 希尔排序代码:
package 排序;
import java.util.Arrays;
public class SheelSort {
public static void main(String[] args) {
int[] arr = {5, 7, 4, 2, 0, 3, 1, 6};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int[] arr) {
for (int grp = arr.length / 2; grp > 0; grp = grp / 2) {
for (int i = grp; i < arr.length; i++) {
//arr[j]arr[ j+grp]比较
for (int j = i - grp; j >= 0; j = j - grp) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
} else {
break;
}
}
}
}
}
}
2. main
方法
在 main
方法中,首先定义了一个整数数组 arr
,并初始化其值为 {5, 7, 4, 2, 0, 3, 1, 6}
。这就是我们要进行排序的原始数组。
int[] arr = {5, 7, 4, 2, 0, 3, 1, 6};
然后调用了 sort
方法,并将数组 arr
作为参数传递给它,目的是对这个数组进行排序操作。
sort(arr);
最后,在排序完成后,使用 Arrays.toString
方法将排序后的数组以字符串的形式输出到控制台,以便直观地查看排序的结果。
System.out.println(Arrays.toString(arr));
3. sort
方法(希尔排序核心逻辑)
sort
方法实现了希尔排序的核心逻辑,下面我们来详细剖析其内部的操作。
-
外层循环(控制间隔变化):
通过for (int grp = arr.length / 2; grp > 0; grp = grp / 2)
这个外层循环,控制着间隔的变化。初始时,间隔grp
被设置为数组长度的一半,然后在每一轮循环后,间隔会减半,直到间隔变为 1。这样就实现了按照逐渐缩小的间隔对数组进行多次预排序的过程。 -
中层循环(遍历子序列):
对于每一个确定的间隔grp
,通过for (int i = grp; i < arr.length; i++)
这个中层循环,从间隔位置开始遍历整个数组。也就是说,对于每一轮间隔为grp
的排序,我们要对以grp
为间隔划分出来的各个子序列进行排序操作。 -
内层循环(子序列内排序):
在中层循环遍历到每个位置i
时,通过内层循环for (int j = i - grp; j >= 0; j = j - grp)
对当前子序列中的元素进行排序。这里的内层循环实现了类似于插入排序的操作,只不过比较的是间隔为grp
的相邻元素。如果发现arr[j] > arr[j + 1]
(这里要注意,因为是按照间隔grp
来比较元素,所以arr[j + 1]
实际上是与arr[j]
间隔为grp
的下一个元素),就通过一个临时变量temp
来进行交换操作,使得子序列中的元素按照插入排序的方式逐渐有序。如果发现当前元素与其间隔为grp
的下一个元素顺序正确(即arr[j] <= arr[j + 1]
),则通过break
语句跳出内层循环,不再继续比较该子序列中更前面的元素。
for (int j = i - grp; j >= 0; j = j - grp) {
if (arr[j] > arr[j + 1]) {
int temp = ();
arr[j] = arr[j + 1];
arr[j + 1] = temp;
} else {
break;
}
}
四、测试结果
当我们运行上述代码时,对于给定的初始数组 {5, 7, 4, 2, 0, 3, 1, 6}
,经过希尔排序后,控制台会输出排序后的数组,其结果应该是 {0, 1, 2, 3, 4, 5, 6, 7}
。