插入排序,从名称可以直观的认为,要把一个数据插入到某个数据集中,有两点要注意,①某个数据集是已经有序的,②这个新数据插入后还保持有序,就要涉及到数据的移动问题。
思路:数组可以认为是分成了两部分,sorted和unSorted,在一开始的时候,可以认为第一个数据已经是sorted,剩下的都是unsorted,at every step,算法把unsorted部分的第一个元素insert到sorted部分的合适位置,直到unsorted部分为空,可以认为操作如下:
直接插入排序代码如下:
public void insertionSort(int[] arr) {
int i, j, newValue;
for (i = 1; i < arr.length; i++) {// begin at the second element
newValue = arr[i];
j = i;
while (j > 0 && arr[j - 1] > newValue) {
arr[j] = arr[j - 1];
j--;
}
arr[j] = newValue;
}
}
仍然看一下消耗时间吧(测得都是移动最多的),时间代码如下:
int[] data = new int[10000];
for(int i=9999; i>=0; i--){
data[i] = 9999-i;
}
long begin = System.currentTimeMillis();
insertionSort(data);
long end = System.currentTimeMillis();
System.out.println("插入用时为:" + (end - begin)+"ms");
插入排序在把unsoted数据插入到sorted数据的时候又可以采用二分查找的方式来找到合适的插入位置,其实只是明显减少了比较次数而已
二分查找方法如下:
public static int binarySearch(int[] arr, int des){
int low=0;
int high = arr.length-1;
while(low<=high){
int middle = (low+high)/2;
if(des == arr[middle]){
return middle;
}else
if(arr[middle] > des){
//中间元素比目标大,肯定在左边,
high = middle-1;
}else
low = middle+1;
}
return -1;
}
与插入方法相结合代码如下
public static int[] binaryInsertSort(int[] data){
int temp;
int low, mid, high;
for (int i = 1; i < data.length; i++) {
temp = data[i];
// 在待插入排序的序号之前进行折半插入
low = 0;
high = i - 1;
while (low <= high) {
mid = (low + high) / 2;
if (temp < data[mid])
high = mid - 1;
else
// low=high的时候也就是找到了要插入的位置,
// 此时进入循环中,将low加1,则就是要插入的位置了
low = mid + 1;
}
//找到了要插入的位置,从该位置一直到插入数据的位置之间数据向后移动
for (int j = i; j >= low + 1; j--){
data[j] = data[j - 1];
}
// low已经代表了要插入的位置了
data[low] = temp;
}
return data;
}
使用时间如下:直接插入:
为什么反而时间使用的多了呢,我把数据换为10万,还是同样,差距一倍左右, 把数据换为1万内随机数,时间消耗还是这样子。
很多人说是测试数据太少了,没有展现出二分的优势来, 我本来想测试100万试一下,结果好久还没出结果我就不想等了,
我觉得还有可能是二分插入比直接插入内循环的时候多了二分查找这些循环的时间,把这个问题贴出来希望有人指点。
PS:第二天(2014-07-18),昨晚上突然想起了这个问题,我发现如果是9999到0 这个数组想要排序变为0到9999这个顺序,二分查找的话其实根本没有展现他的优势,因为每次要插入的新数据都是插入到前面sorted数组的最前面,在这里二分查找并没有展现优势,所以效率不高可以理解,不过随机数还是这样子的我还是没有理解。