插入排序法及其改进

探讨下插入排序法的传统代码及改进代码

过程:声明大小为100000的整型数组arr和数组help,Math.random()*10000000生成随机数,将生成的随机数同时赋值给数组arr和help,arr使用两种插入排序测试运行时间,而help使用Arrays.sort()排序,help用于对数器函数对数使用,在保证排序正确的前提下比较两种插入排序的运行效率。

代码如下:

package 排序问题;

import java.util.Arrays;

public class 插入排序 {

	public static void main(String[] args) {
		int[] arr = new int[100000];
		int[] help = new int[100000];
		for(int i=0;i<100000;i++){
			arr[i] = (int)(10000000*Math.random());
			help[i] = arr[i];
		}
		
		Arrays.sort(help);
		long startTime=System.currentTimeMillis();
		//经典插入排序
		for(int i=1;i<100000;i++)
		for(int j=i;j>0&&arr[j]<arr[j-1];j--){
				int t = arr[j];
				arr[j] = arr[j-1];
				arr[j-1] = t;
		}
		
		/*
		//优化后的插入排序
		for(int i=1;i<100000;i++)
		{
			int j = i;
			int e = arr[j];
			while(j>=1&&e<arr[j-1]){
				arr[j] = arr[j-1];
				j--;
			}
			arr[j] = e;
		}
		*/
	     long endTime=System.currentTimeMillis();
	     float excTime=(float)(endTime-startTime)/1000;
	    System.out.println("run time is "+excTime+"s");
		String s = compare(arr,help);
		System.out.println(s);
				
	}

	//对数器
	private static String compare(int[] arr, int[] help) {
		for(int i=0;i<100000;i++)
		{
			if(arr[i]!=help[i])
			{
				return "Sort is error";
			}
		}
		
		return "Sort is ok";
	} 

}

先介绍下传统插入排序的思路:

先从第二个数组元素开始遍历到第n个数组元素(定义变量i从1增长到99999),对每个数组元素进行循环操作:定义变量j=i,循环条件 j不是数组第一个元素并且当前第j个元素小于第j-1个元素,交换两个元素位置,j--;两层for循环结束,即完成了排序。

测试一下传统插入排序对含有100000个随机数的数组的排序时间:


可以看出排序时间是12.7秒,排序过程也是正确的。


再介绍下改进版的插入排序思路:

定义变量i从1增长到99999,对第i个数组元素进行如下操作:定义变量j=i,定义中间变量e存储第j个元素的值,进行一个while循环,循环条件是 j>=1&&e<arr[j-1](当j是第二个元素及以后的元素时才有向前位移的意义,并且第i个元素的值小于第j-1个元素的值才能进行位移),循环内容是 将第j-1个元素的值赋值给第j个元素的值;执行完while循环后,当前第j-1个元素的值会大于等于第i个元素暂存在e的值,将第i个元素暂存值e赋值给第j个元素,即完成对第i个数在合适位置上的插入。对每个i进行完相应的操作时,即完成了对数组的改良版插入排序。

接着测试一下改良版插入排序对含有100000个随机数的数组的排序时间:


运行时间是9.6秒,排序过程也是正确的。


分析:

案例:3421

(1)传统插入排序进行排序过程:

对第二个元素4,判断4是否小于第一个元素3,判断结果是false,跳出循环

对第三个元素2,判断2是否小于第二个元素4,判断结果是true,交换2与4,得到:3241;判断第二个元素2是否小于第一个元素3,判断结果是true,交换2与3,得到:2341;由于2现在是第一个元素,所以跳出循环

对第四个元素1,判断第四个元素1是否小于第三个元素4,判断结果是true,交换4与1,得到:2314;判断第三个元素1是否小于第二个元素3,判断结果是true,交换1和3,得到:2134;判断第二个元素1是否小于第一个元素2,判断结果是true,交换2和1,得到:1234;由于1现在是第一个元素,所以跳出循环。


由于每一次交换需要进行三次操作,上述案例中,传统插入排序进行了5次交换,即总共进行了15次操作。

(2)改良版插入排序进行排序过程:

对第二个元素4进行暂存操作,将4赋值给中间变量e,判断e是否小于第一个元素3,判断结果是false,跳出循环

对第三个元素2进行暂存操作,将2赋值给中间变量e,判断e是否小于第二个元素4,判断结果是true,将第二个元素4赋值给第三个元素,得到:3441;判断e是否小于第一个元素3,判断结果是true,将第一个元素3赋值给第二个元素,得到:3341;由于不存在第0个元素,所以跳出循环;将e赋值给第一个元素,得到:2341

对第四个元素1进行暂存操作,将1赋值给中间变量e,判断e是否小于第三个元素4,判断结果是true,将第三个元素4赋值给第四个元素,得到:2344;判断e是否小于第二个元素3,判断结果是true,将第二个元素3赋值给第三个元素,得到:2334;判断e是否小于第一个元素2,判断结果是true,将第一个元素2赋值给第二个元素,得到2234;由于不存在第0个元素,所以跳出循环;将e赋值给第二个元素,得到:1234


对第三个元素而言,先进行暂存操作,再进行两次数组元素赋值操作,最后将暂存值e赋值给第一个元素,一共进行了4次操作;相应的流程判断,可知改良版排序一共进行了10次操作


总结:改良版插入排序可以简化传统插入排序中冗余的交换操作,对数组元素的依次位移减少了元素交换时赋值的操作次数,从而提升了排序的效率。

猜你喜欢

转载自blog.csdn.net/A1344714150/article/details/80781215