探讨下插入排序法的传统代码及改进代码
过程:声明大小为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次操作
总结:改良版插入排序可以简化传统插入排序中冗余的交换操作,对数组元素的依次位移减少了元素交换时赋值的操作次数,从而提升了排序的效率。