1. 排序思路
- 不断将原数组分组,每组进行"简单插入排序"
- 分组方式为:
- 第一次分 length/2 组,
- 第二次分 length/2/2 组,
- 第三次分 length/2/2/2 组,
- …,
- 以此类推,最后一次分为 1 组
- 结束分组和分别的插入排序,整个数组的排序即完成
- 注意:插入方法有"交换法"(效率低)和"移位法"(高效)两种
- 另见:简单插入排序
- “希尔排序” 是对 “简单插入排序” 的优化
- 若出现插入数较小时,简单插入排序效率变低
- 如 [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
2. 代码实现
/**
* 希尔排序(缩小增量排序)
* 思路:
* - 不断将原数组分组,每组进行"简单插入排序"
* - 分组方式为:
* 第一次分 length/2 组,
* 第二次分 length/2/2 组,
* 第三次分 length/2/2/2 组,
* ...,
* 以此类推,最后一次分为 1 组
* - 结束分组和分别的插入排序,整个数组的排序即完成
* - 注意:插入方法有"交换法"(效率低)和"移位法"(高效)两种
* @param originalArray - 原始数组
* @return - 排序后数组(不改变原始数组)
*/
// 交换法(低效)
public static int[] shellSortByExchanging(int[] originalArray) {
// 1. 复制数组
int[] sortedArray = new int[originalArray.length];
for (int i = 0; i < originalArray.length; i++) {
sortedArray[i] = originalArray[i];
}
// 2. 大循环,每轮循环将数组分成 gap 组,gap = gap / 2
for (int gap = sortedArray.length / 2; gap > 0; gap /= 2) {
// 2.1 设置临时int变量,用于交换
int tempNumber = 0;
// 2.2 中循环和小循环,将每组用"选择排序"的方式分别排序
for (int i = gap; i < sortedArray.length; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
// 若 前 > 后:交换
if (sortedArray[j] > sortedArray[j + gap]) {
tempNumber = sortedArray[j];
sortedArray[j] = sortedArray[j + gap];
sortedArray[j + gap] = tempNumber;
}
}
}
}
// 3. 返回排好序的数组
return sortedArray;
}
// 优化 - 移位法(高效)
public static int[] shellSortByShifting(int[] originalArray) {
// 1. 复制数组
int[] sortedArray = new int[originalArray.length];
for (int i = 0; i < originalArray.length; i++) {
sortedArray[i] = originalArray[i];
}
// 2. 大循环,每轮循环将数组分成 gap 组,gap = gap / 2
for (int gap = sortedArray.length / 2; gap > 0; gap /= 2) {
// 对每个组用"移位"的方式执行"插入排序"
// 2.1 中循环,每一轮即一组,找到每组"乱序表"的首位 i (初始下标为gap)
for (int i = gap; i < sortedArray.length; i++) {
// (1) 设置int变量储存本轮循环要插入的位置下标;设置int变量储存要插入的数值("无序表"首位数)
int positionForInserting = i;
int insertNumber = sortedArray[i];
// (2) 小循环:遍历"有序表",将"无序表"的首位与"有序表"逐个比较,寻找插入点
// 若达到"有序表"的首位,或 待插入数值 >= positionForInserting - gap 数值(找到插入点),停止本轮小循环
while (positionForInserting - gap >= 0 && insertNumber < sortedArray[positionForInserting - gap]) {
sortedArray[positionForInserting] = sortedArray[positionForInserting - gap];
positionForInserting -= gap;
}
// (3) 将 待插入数值 插入 待插入点
sortedArray[positionForInserting] = insertNumber;
}
}
// 3. 返回排好序的数组
return sortedArray;
}