import java.util.Random;
/***
* Shell排序:(以升序为例)
*
* (几个典型的部分有序数组:
*
* 一、数组中每个元素距离它的最终位置都不远
*
* 二、一个有序的大数组接一个小数组
*
* 三、数组中只有几个元素的位置不正确。)
*
* 思想:
*
* 【使数组中任意间隔为h的元素都是有序的,这样的数组被称为h有序数组。】
*
* 实现方法:
*
* 【1、将h个子数组独立的排序。
*
* 2、(更简单)将每一个h-子数组中的元素移到比他大的元素之前,
*
* 只需要在插入排序的代码中将移动元素的距离有1改为h即可。
*
* 这样,Shell排序的实现就转化成了一个类似于插入排序但使用不同增量的过程。】
*
* 适用的数组:
*
* 【小数组,也可以适用于大数组,对任意排序数组的表现也很好。】
*
* 个人理解:
*
* 【Shell排序是插入排序的改进,插入排序最适用于部分有序数组,
*
* 而Shell排序就是事先将数组变成了部分有序数组,最后在来一趟插入排序,
*
* 从而使数组整体有序。】
*
* 书中解释:
*
* 【Shell排序高校的原因是他权衡了子数组的规模和有序性。
*
* 排序之初,各个子数组都很短,排序后子数组都是部分有序的,这两种情况都很适合插入排序。
*
* 子数组的部分有序取决于递增序列的选择。】
*
* @author LuodiJack
*
*/
public class Shell {
@SuppressWarnings("rawtypes")
public static void sort(Comparable[] a) {
int N = a.length;
int h = 1;
while (h < N / 3) {// 递增序列(可以事先将其存储在数组中)
h = h * 3 + 1;// 目前没有最优的递增序列,只能凭借经验,这个递增序列可以适用大部分的实际问题.
}
while (h >= 1) {
for (int i = h; i < N; i++) {// 将a[i]插入到a[i-h],a[i-2*h],a[i-3*h],a[i-4*h],a[i-5*h]......中(和插入排序一样)
for (int j = i; j >= h && Template.less(a[j], a[j - h]); j -= h) {
Template.exch(a, j, j - h);
}
}
h /= 3;
}
}
public static String toString(Integer[] a) {
String str = "";
for (int i = 0; i < a.length; i++) {
str += a[i] + " ";
}
return str;
}
public static void show(Integer[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
Random random = new Random();
final int MAX = 1000000;
Integer[] a = new Integer[MAX];
Integer[] b = new Integer[MAX];
for (int i = 0; i < MAX; i++) {
b[i] = a[i] = random.nextInt(MAX);
}
ShowTime st1 = new ShowTime();
sort(a);
st1.showTime();
ShowTime st2 = new ShowTime();
Insertion.sort(b);
st2.showTime();
if (toString(a).equals(toString(b))) {
System.out.println("yes");
} else {
System.out.println("no");
show(a);
show(b);
}
}
}
文中用到的less()、exch()方法,详见类模板。(排序算法笔记____1)
http://blog.csdn.net/a199581/article/details/50651401