三.插入排序(直接插入排序+希尔排序)
1.直接插入排序
根据比较类Comparator来判断是升序排列还是降序排列
若Comparator中的compare函数返回值是a > b ? 1 : (a < b ? -1 : 0),则是升序排列
compare函数返回值是a > b ? -1 : (a < b ? 1 : 0),则是降序排列
排序思路:
①假定数组第一个元素是有序序列,第二个元素到最后一个元素是无序序列
②从无序序列最开始元素开始遍历
③从有序序列一次从后往前比较,若发现不满足排序规则的元素,有序序列向后移动一位
④重复③,知道找到该元素所在的位置
⑤重复②~④
时间复杂度:O(n^2)
空间复杂度:O(1)
public static <T> void insertSort(T[] t, Comparator<? super T> comparator) {
int size = t == null ? 0 : t.length;
T temp; int j;
for(int i = 1; i < size; i++) {
temp = t[i];
for(j = i; j > 0; j--) {
if(comparator.compare(temp, t[j - 1]) < 0) {
t[j] = t[j - 1];
} else {
break;
}
}
t[j] = temp;
}
}
2.希尔排序
根据比较类Comparator来判断是升序排列还是降序排列
若Comparator中的compare函数的返回值是:a > b ? 1 : (a < b ? -1 : 0),则是升序排列
若compare函数的返回值是:a > b ? -1 : (a < b ? 1 : 0),则是降序排列
排序思路:
①选择一个增量序列,增量序列最后一个为1
②假设增量序列个数为k,则对排序序列进行k趟排序
③每趟排序,根据对应的增量,将排序序列分成长度为m的子序列,对各自序列进行直接插入排序
时间复杂度:O(n^1.3)
空间复杂度:O(1)
public static <T> void shellSort(T[] t, Comparator<? super T> comparator) {
int size = t == null ? 0 : t.length;
int dk = size / 2;
while(dk >= 1) {
for(int i = dk; i < size; i++) {
// 若第i个元素大于i-dk元素,直接插入。小于的话,移动有序表后插入
if(comparator.compare(t[i], t[i - dk]) < 0) {
int j = i - dk;
T temp = t[i]; // 临时存储待排序序列
while(comparator.compare(temp, t[j]) < 0) {
t[j + dk] = t[j];
j -= dk; // 元素后移
if(j < 0) break; // 如果j小于0,则跳出此次循环
}
t[j + dk] = temp; // 插入到正确位置
}
}
dk = dk / 2;
}
}
测试程序
disturbOrder(T[] t)方法请查看Java算法-排序-交换排序
public static void main(String[] args) {
Integer[] numbers = new Integer[9999];
for(int i = 0; i < numbers.length; i++) {
numbers[i] = i;
}
disturbOrder(numbers);
long start4 = System.currentTimeMillis();
insertSort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a > b ? 1 : (a < b ? -1 : 0);
}
});
long end4 = System.currentTimeMillis();
System.out.println("插入排序耗时:" + (end4 - start4));
disturbOrder(numbers);
long start5 = System.currentTimeMillis();
shellSort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a > b ? 1 : (a < b ? -1 : 0);
}
});
long end5 = System.currentTimeMillis();
System.out.println("希尔排序耗时:" + (end5 - start5));
}