排序算法之希尔排序
背景
希尔排序是对插入排序的优化,如果一个长度为N的数组中,数值最小的元素恰好在数组最末端,则将该元素归位(假设从小到大插入排序)得移动N-1次。
特点
相对于插入排序是移动相邻元素,希尔排序移动的是不相邻的元素,先对数组的局部进行排序,最终借助插入排序将局部有序的数组排序
中心思想
使数组中任意间隔为h的元素都是有序的
操作步骤
- 先找出待排序数组的h序列,可通过h = h * 3 + 1; h < N得到(h=1,4,7…;h最小是1)
- 对每个h插入排序,得到一个h有序数组(h有序数组必须是一个由h个有序子数组构成的数组,每个子数组中的元素都是由原数组中间隔为h的元素组成)
举例
有一N=16的无序数组,h=4时如下图:
得到了4个子数组后,一种方式是分别对4个子数组进行插入排序,但此种方式可能需要3个循环(外循环来选择子数组,两个内循环来对该子数组进行插入排序)。一种简单的做法是将每个元素都和它之前相距h的元素进行插入排序(该例中可从i=4元素开始插入排序),即比较的轨迹不再沿着子数组。从M开始,M和L插入排序,H和E插入排序,L和E插入排序,E和A插入排序,P和M和L插入排序…最终R和L、E、A插入排序
代码实现
public void sort(int[] a) {
int N = a.length;
int h = 1;
while(h * 3 + 1 < N){
h = h * 3 + 1;
}//得到h序列中最大值
while(h > 0){
//对i之前所有间隔为h的元素进行插入排序
for(int i = h; i < N; i++){
for(int j = i; j > h; j = j - h){
if (a[j-h] > a[j]) {
swap(a, j-h, j);
}
}
}
h = (h - 1) / 3;//换下一个h
}
}
private void swap(int[] a, int m, int n){
int temp = a[m];
a[m] = a[n];
a[n] = a[m];
}