P115
package org.test.algorithm;
/**
* 插入排序
* 从数组第二个元素开始,返回向开头逐一检测每个元素,如果小于前面的某一个,则和他交换位置
*
* T(n) = O(n*n)
* @author Administrator
*
*/
public class InsertSort {
/**
* 算法二改进C:
* 优化内循环
* @param srcArr
* @return
*/
public int[] insertSortElegantC(int[] srcArr){
if(srcArr.length<2){
return srcArr;
}
//中间交换变量
int tmp =0;
int j=0;
for(int i=1;i<srcArr.length;i++){
//内循环其实是在把srcArr[i]向前逐一比对,tmp的值始终是srcArr[i],所以从内循环取出
tmp = srcArr[i];
for(j=i;j>0&&srcArr[j-1]>tmp;j--){
//swap
//此处隐含了一步:tmp = srcArr[j]; 因为tmp值一直没有变化
srcArr[j] = srcArr[j-1];
}
srcArr[j] = tmp;//最终j停止的位置,就是srcArr[i]最终的位置
}
return srcArr;
}
/**
* 算法二改进B:
* swap内联进来
* @param srcArr
* @return
*/
public int[] insertSortElegantB(int[] srcArr){
if(srcArr.length<2){
return srcArr;
}
//中间交换变量
int tmp =0;
for(int i=1;i<srcArr.length;i++){
for(int j=i;j>0&&srcArr[j]<srcArr[j-1];j--){
//swap
tmp = srcArr[j];//此处还可以优化,每次都是在把同样的值赋给tmp(x[i]),所以可以从内循环中移出来
srcArr[j] = srcArr[j-1];
srcArr[j-1] = tmp;
}
}
return srcArr;
}
/**
* 算法二改进A:
* 循环 更简洁优雅
* 缺点:swap函数调用改成内联效率更高
* @param srcArr
* @return
*/
public int[] insertSortElegantA(int[] srcArr){
if(srcArr.length<2){
return srcArr;
}
//中间交换变量
int tmp =0;
for(int i=1;i<srcArr.length;i++){
for(int j=i;j>0&&srcArr[j]<srcArr[j-1];j--){
//swap
swap(srcArr,j,j-1);
}
}
return srcArr;
}
/**
* 数组交换元素
* @param srcArr
* @param idx1
* @param idx2
*/
private void swap(int[] srcArr,int idx1,int idx2){
int tmp = srcArr[idx1];
srcArr[idx1] = srcArr[idx2];
srcArr[idx2] = tmp;
}
/**
* 算法二:
* Usefull 实用
*
* 但代码不简洁
*
*
* 扑克牌,抓牌时排序算法,抓到一张后,从最后向前逐一比对,srcArr[j]小于srcArr[j-1]则交换,直到开头
* @param srcArr
* @return
*/
public int[] insertSortUsefull(int[] srcArr){
if(srcArr.length<2){
return srcArr;
}
//中间交换变量
int tmp =0;
//内循环索引
int j = 0;
for(int i=1;i<srcArr.length;i++){
//i外层循环当前位置
j = i;
/**
* 内循环,当前元素向数组0索引方向推进,遇到比自己大 的就加换位置
* 内循环结果:i之前元素都升序排列
*/
while(j>0&&srcArr[j]<srcArr[j-1]){
//swap
tmp = srcArr[j];
srcArr[j] = srcArr[j-1];
srcArr[j-1] = tmp;
j--;
}
}
return srcArr;
}
/**
* 算法一:
* ugly丑陋的实现
*
* 类似银行取号排队,你来晚了,从头开始查看每个人手里拿的号码,要是比他小,就和他换位置
* 会导致{3,1,2,4}
* {1,3,2,4}
* {2,3,1,4}这种状态,浪费了时间
* @param srcArr
* @return
*/
public int[] insertSortUgly(int[] srcArr){
if(srcArr.length<2){
return srcArr;
}
int tmp = 0;
for(int i=1;i<srcArr.length;i++){
for(int j=0;j<i;j++){
if(srcArr[i]<srcArr[j]){
tmp =srcArr[i];
srcArr[i]=srcArr[j];
srcArr[j] = tmp;
}
}
}
return srcArr;
}
}
package org.test.algorithm;
import junit.framework.TestCase;
/**
* todo: tmp移出内循环?
* @author Administrator
*
*/
public class TestInsertSort extends TestCase {
public void testInsertSort() {
int[] arr = new int[]{3,4,5,89,2,3,0,56,7,1,4,567,3,87};
final int SIZE = 1000000;
arr = new int[SIZE];
for(int i=0;i<SIZE;i++){
arr[i] = (int)Math.random()*100;
}
long start = System.nanoTime();
//逐一测试时间 结果和书上不同,不知道是不是编译器有什么优化了
// int[] newarr = new InsertSort().insertSortElegantC(arr);//time used:(ns)5936788
// int[] newarr = new InsertSort().insertSortElegantA(arr);//time used:(ns)5576687
// int[] newarr = new InsertSort().insertSortElegantB(arr);//time used:(ns)5728661
// int[] newarr = new InsertSort().insertSortUgly(arr);//long long time
int[] newarr = new InsertSort().insertSortUsefull(arr); //time used:(ns)5865829
long last = System.nanoTime()-start;
System.out.println("time used:(ns)"+last);
// for(int i=0;i<newarr.length;i++){
// System.out.println(newarr[i]);
// }
}
}