希尔排序是基于插入排序的算法
排序算法类模板:
https://blog.csdn.net/chenghan_yang/article/details/83002422
希尔排序的步骤
- 确定分组间隔,并确定递增序列
- 对原数组进行等间隔分组,遵循一定的规则,类似于{n1,n2,n3,n4,n5,n6} 以3为间隔,可分为{n1,n4}、{n2,n5}、{n3,n6}
- 对分组内的元素进行插入排序
- 重复1和2,直到分组间隔减为1
package sort;
public class Example {
public static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
public static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
public static void show(Comparable[] a) {
for(int i = 0; i<a.length; i++) {
System.out.print(a[i] + " ");
}
}
public static boolean isSorted(Comparable[] a) {
for(int i = 1; i < a.length; i++) {
if(less(a[i],a [i-1])) return false;
}
return false;
}
}
package shell_sort;
import java.util.Arrays;
import sort.Example;
public class Shell extends Example
{
public static void sort(Comparable[] a)
{
int N = a.length;
int h = 1;
while (h < N/3) h = 3*h + 1;
int count1 = 0;
int count2 = 0;
while (h >= 1)
{
System.out.println("【轮次】——————————下面进行——————————" + ++count1 +"轮排序" + "初始序列为" + Arrays.toString(a));
System.out.println();
for (int i = h; i < N; i++)
{
for(int j = i; j >= h && less(a[j], a[j-h]); j -= h)
{
System.out.println("--进行" + count1 +"轮排序" +"中的" + ++count2 + "次交换");
System.out.println("【交换的元素】为【" + a[j] + "】和【" + a[j-h] + "】");
exch(a, j, j-h);
System.out.println(Arrays.toString(a));
System.out.println();
}
}
count2 = 0;
h=h/3;
}
}
}
package shell_sort;
public class Test {
public static void main(String[] args) {
Integer[] a = {1,66,7,4,8,9,3,25,64,13,65,13,86,42,56} ;
Shell.sort(a);
}
}
---
【轮次】——————————下面进行——————————1轮排序初始序列为[1, 66, 7, 4, 8, 9, 3, 25, 64, 13, 65, 13, 86, 42, 56]
--进行1轮排序中的1次交换
【交换的元素】为【56】和【66】
[1, 56, 7, 4, 8, 9, 3, 25, 64, 13, 65, 13, 86, 42, 66]
【轮次】——————————下面进行——————————2轮排序初始序列为[1, 56, 7, 4, 8, 9, 3, 25, 64, 13, 65, 13, 86, 42, 66]
--进行2轮排序中的1次交换
【交换的元素】为【9】和【56】
[1, 9, 7, 4, 8, 56, 3, 25, 64, 13, 65, 13, 86, 42, 66]
--进行2轮排序中的2次交换
【交换的元素】为【3】和【7】
[1, 9, 3, 4, 8, 56, 7, 25, 64, 13, 65, 13, 86, 42, 66]
--进行2轮排序中的3次交换
【交换的元素】为【13】和【56】
[1, 9, 3, 4, 8, 13, 7, 25, 64, 56, 65, 13, 86, 42, 66]
--进行2轮排序中的4次交换
【交换的元素】为【13】和【25】
[1, 9, 3, 4, 8, 13, 7, 13, 64, 56, 65, 25, 86, 42, 66]
--进行2轮排序中的5次交换
【交换的元素】为【42】和【56】
[1, 9, 3, 4, 8, 13, 7, 13, 64, 42, 65, 25, 86, 56, 66]
【轮次】——————————下面进行——————————3轮排序初始序列为[1, 9, 3, 4, 8, 13, 7, 13, 64, 42, 65, 25, 86, 56, 66]
--进行3轮排序中的1次交换
【交换的元素】为【3】和【9】
[1, 3, 9, 4, 8, 13, 7, 13, 64, 42, 65, 25, 86, 56, 66]
--进行3轮排序中的2次交换
【交换的元素】为【4】和【9】
[1, 3, 4, 9, 8, 13, 7, 13, 64, 42, 65, 25, 86, 56, 66]
--进行3轮排序中的3次交换
【交换的元素】为【8】和【9】
[1, 3, 4, 8, 9, 13, 7, 13, 64, 42, 65, 25, 86, 56, 66]
--进行3轮排序中的4次交换
【交换的元素】为【7】和【13】
[1, 3, 4, 8, 9, 7, 13, 13, 64, 42, 65, 25, 86, 56, 66]
--进行3轮排序中的5次交换
【交换的元素】为【7】和【9】
[1, 3, 4, 8, 7, 9, 13, 13, 64, 42, 65, 25, 86, 56, 66]
--进行3轮排序中的6次交换
【交换的元素】为【7】和【8】
[1, 3, 4, 7, 8, 9, 13, 13, 64, 42, 65, 25, 86, 56, 66]
--进行3轮排序中的7次交换
【交换的元素】为【42】和【64】
[1, 3, 4, 7, 8, 9, 13, 13, 42, 64, 65, 25, 86, 56, 66]
--进行3轮排序中的8次交换
【交换的元素】为【25】和【65】
[1, 3, 4, 7, 8, 9, 13, 13, 42, 64, 25, 65, 86, 56, 66]
--进行3轮排序中的9次交换
【交换的元素】为【25】和【64】
[1, 3, 4, 7, 8, 9, 13, 13, 42, 25, 64, 65, 86, 56, 66]
--进行3轮排序中的10次交换
【交换的元素】为【25】和【42】
[1, 3, 4, 7, 8, 9, 13, 13, 25, 42, 64, 65, 86, 56, 66]
--进行3轮排序中的11次交换
【交换的元素】为【56】和【86】
[1, 3, 4, 7, 8, 9, 13, 13, 25, 42, 64, 65, 56, 86, 66]
--进行3轮排序中的12次交换
【交换的元素】为【56】和【65】
[1, 3, 4, 7, 8, 9, 13, 13, 25, 42, 64, 56, 65, 86, 66]
--进行3轮排序中的13次交换
【交换的元素】为【56】和【64】
[1, 3, 4, 7, 8, 9, 13, 13, 25, 42, 56, 64, 65, 86, 66]
--进行3轮排序中的14次交换
【交换的元素】为【66】和【86】
[1, 3, 4, 7, 8, 9, 13, 13, 25, 42, 56, 64, 65, 66, 86]
- 代码解读 - 隐式的分组交换
- h = 1, while(h < N/3) { h = 3*h + 1} 假设的递增序列,当N=15, h=13。确定这样一个序列是影响性能的关键,但至今没有文献证明有性能最高的序列,所以不重点理解。
- 上面确定了h, 也就确定了步长。 一轮操作后步长以h/3 递减, 也就分别是h=13, 4, 1
- for的两个循环,其实是对每一组进行并行的插入排序。代码并不是先确认分组再进行排序的,是每次交换元素都在分组内进行,用h为步长。如[1,66,7,4,8,9,3,25,64,13,65,13,86,42,56], N=15
——————————————————————————————————————
第一轮h = 13, 可以分两组
[1, 42]
[66 , 56] -> [56,66]
第一轮排序后的结果为(黄标为交换过的元素):
[1 56 7 4 8 9 3 25 64 13 65 13 86 42 66]
——————————————————————————————————————
第二轮h = 4,所有元素被分成三组,分别是
[1 8 64 86]
[56 9 13 42]
[7 3 65 66]
[4 25 13]
第二轮排序结果为
[1, 9, 3, 4, 8, 13, 7, 13, 64, 42, 65, 25, 86, 56, 66]
——————————————————————————————————————
第三轮h = 1所有元素就是一组,进行插入排序
循环开始的三次分别定位的是三组的开头元素,所以是实现并行的插入排序
- 实际应用
算法第四版P262:如果你需要解决一个排序问题而又没有系统排序函数可用(例如直接接触硬件或是运行于嵌入式系统中的代码),可以先用希尔排序,然后再考虑是否值得将它替换为更加复杂的排序算法