一、前言
希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
-
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
-
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
二、原理
基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
简单来说:根据数组的长度length分成几组元素,这个分组规则可以自己定义。比如数组长度为 10,第一次分两组,分组元素长度为 5;第二次根据数组的长度 5再分两组,分组后的数组长度为 2;第三次根据数组长度2再分组,分组后的长度为1,满足 增量减至 1 ,至此算法便终止。这个过程的分组规则为 length/2。遍历一次分组,组内的元素排序。
三、图例
数组:{49,38,65,97,76,13,27,49,55,04} 按 5,2,1 的增量序列处理,静态图如下所示:
四、代码
@Test
public void shell(){
int[] nums = {49,38,65,97,76,13,27,49,55,04};
int length = nums.length;
System.out.println("遍历前:"+ Arrays.toString(nums));
int len = length;
while (true){
// 每次分组递减量
len /=2;
System.out.println("len=="+len);
// 遍历分组的元素
for (int i=0;i<len;i++){
//这个循环里其实就是一个插入排序
for (int j=i+len;j<length;j +=len){
// 获取前面的元素的索引(下标)。 nums[tmpLen+len] 递增量后的元素
int tmpLen = j-len;
while (tmpLen >=0 && nums[tmpLen] > nums[tmpLen+len]){
// 元素交换位置如: tmpLen 与 tmpLen+len 交换位置。
int tmp = nums[tmpLen];
nums[tmpLen] = nums[tmpLen+len];
nums[tmpLen+len] = tmp;
tmpLen -= len;
System.out.println("tmpLen:"+tmpLen);
}
System.out.println("j=="+j);
}
}
// 分组递减量为1时,则结束遍历
if (len == 1){
break;
}
}
System.out.println("遍历后:"+ Arrays.toString(nums));
}
@Test
public void shell2(){
int[] arr = {49,38,65,97,76,13,27,49,55,4};
int length = arr.length;
System.out.println("遍历前:"+ Arrays.toString(arr));
int gap = 1;
while (gap < length/3) {
gap = gap * 3 + 1;
}
System.out.println("gap:"+gap);
// 分组遍历
while (gap > 0) {
// 元素遍历
for (int i = gap; i < length; i++) {
// 后面的元素 分组递增量:gap
int tmp = arr[i];
// 前面元素的索引
int j = i - gap;
// 元素大小比较
while (j >= 0 && arr[j] > tmp) {
// arr[j] > tmp 前面元素大于后面元素,则前面元素暴力覆盖后面元素(j + gap)
arr[j + gap] = arr[j];
j -= gap;
}
arr[j + gap] = tmp;
}
// 对一个数进行下舍入
gap = (int) Math.floor(gap / 3);
}
System.out.println("遍历后:"+ Arrays.toString(arr));
}
学习地址:
https://baike.baidu.com/item/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F/3229428?fr=aladdin