《编程珠玑2》读书笔记-插入排序

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]);
//		}
	}
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值