一、插入排序
插入排序思想:回想一下我们打扑克的时候摸牌的过程,有时喜欢把牌按大小顺序排列起来,每次摸到的牌和手中的牌比较,如果小的话就往前找位置,一直移到比它小的牌后面,比它大的牌前面,然后将牌插入,一直到牌摸完,我们手中的牌最后就是有序的。而插入排序就像我们打扑克牌摸牌的过程是一样的。
来看代码:
public void insertSort(int[] arr) {
for(int i = 1; i < arr.length; i++) {
// 新进待比较的值
int new_key = arr[i];
// 前面已经有序的最后一个元素下标
int j = i - 1;
// 寻找待插入的位置
while(j >=0 && new_key < arr[j]) {
// 向后移动腾出一个位置插入
arr[j + 1] = arr[j];
j --;
}
// 找到位置j 把new_key 放在比它小的元素后面
arr[j + 1] = new_key;
}
}
由上面的代码,可以看出,如果数组arr有序的话,会做很多 无谓的比较操作和最后一步赋值的操作,所以我们可以继续优化一下,优化后的代码如下:
public void insertSort1(int[] arr) {
for(int i = 1; i < arr.length; i++) {
// 优化点:只有新进的元素比前面已经有序的最后一个元素小的时候才去比较及移动
if(arr[i] > arr[i - 1]) continue;
// 新进待比较的值
int new_key = arr[i];
// 前面已经有序的最后一个元素下标
int j = i - 1;
// 寻找待插入的位置
while(j >=0 && new_key < arr[j]) {
// 向后移动腾出一个位置插入
arr[j + 1] = arr[j];
j --;
}
// 找到位置j 把new_key 放在比它小的元素后面
arr[j + 1] = new_key;
}
}
二、希尔排序:
希尔排序是插入排序的一种变形,又称“缩小增量排序”,基本思想是将待排序列按我们的增量分组,每组按照我们基本的插入排序排序,直到我们的增量减至为1整个序列为一组,此时我们的序列已经基本有序,最后做一次基本插入排序便使得待排序列有序,这样大量减少了元素的移动次数,从而提高了效率。下面来看代码。
public void shellSort(int[] arr) {
for (int di = arr.length / 2; di >= 1; di /= 2) {
for (int i = di; i < arr.length; i += di) {
if (arr[i] > arr[i - di]) {
continue;
}
int new_key = arr[i];
int j = i - di;
while (j >= 0 && new_key < arr[j]) {
arr[j + di] = arr[j];
j -= di;
}
arr[j + di] = new_key;
}
}
}
下面来看看性能比较:
如下是数据生成类:
public class DataProduct {
public static int[] getData() {
int[] arr = new int[100000];
Random r = new Random();
for(int i = 0; i < arr.length; i++) {
arr[i] = r.nextInt(100);
}
return arr;
}
public static int[] cloneArr(int[] arr) {
int[] cloneArr = new int[arr.length];
System.arraycopy(arr, 0, cloneArr, 0, arr.length);
return cloneArr;
}
}
测试如下:
public static void main(String[] args) {
InsertSort in = new InsertSort();
int[] arr1 = DataProduct.getData();
int[] arr2 = DataProduct.cloneArr(arr1);
int[] arr3 = DataProduct.cloneArr(arr1);
long start1 = System.currentTimeMillis();
in.insertSort(arr1);
long end1 = System.currentTimeMillis();
System.out.println("insort cost time:" + (end1 - start1));
long start2 = System.currentTimeMillis();
in.insertSort1(arr2);
long end2 = System.currentTimeMillis();
System.out.println("insort1 cost time:" + (end2 - start2));
long start3 = System.currentTimeMillis();
in.shellSort(arr3);
long end3 = System.currentTimeMillis();
System.out.println("shellSort cost time:" + (end3 - start3));
}
耗时结果如下: