特点:样本小且基本有序情况下效率高,并且稳定。
选择排序、冒泡排序、插入排序区别:
- 选择排序,每次选择最大/小值放到前面合适位置,每轮内层循环交换一次。排好的子数组有序。
- 冒泡排序,每次两两比较都交换,将最大/小值交换到子数组位置。排好子数组有序。
- 插入排序,每次插入后子数组都有序,且不是根据最大/最小值排序。
思路 :前i个数字有序,第i+1个数字和前面i个数字依次比较并交换顺序插入到前i个数字合适。和最小值冒泡排序有点像。
代码思路:从第二个位置开始,和前面有序数字两两比较交换。但是优化后的插入排序,只需要交换1次。
时空复杂度:平均O(n^2),最坏O(n^2),最好O(n)--内层循环比较一次后退出(加break后,时间迅速降低)
方法1:普通方式----和前面排好序列两两比较交换
时间复杂度分析见代码注释部分
private void insertSort(){
int[] arrayRandom = new int[10];
int[] arrayRandomCalcul = new int[arrayRandom.length];
Random random = new Random();
for (int i = 0; i < arrayRandom.length; i++) {
arrayRandom[i] = random.nextInt(arrayRandom.length);
}
System.arraycopy(arrayRandom, 0, arrayRandomCalcul, 0, arrayRandom.length);
logger.info(JSON.toJSONString(arrayRandomCalcul));
for (int i=1;i<arrayRandomCalcul.length;i++){//i=1执行1次,i<len执行n+1次,i++执行n次,共2n+2次
for (int j = i;j > 0 ;j--){//j=i执行1次,j>0执行i+1次,j--执行i次,共2i+2次
if (arrayRandomCalcul[j] < arrayRandomCalcul[j-1])swap(arrayRandomCalcul,j,j-1);//执行3次
else break;//这样在排好序情况下,才会中断j>0的判断,减少执行次数
}
}
logger.info(JSON.toJSONString(arrayRandomCalcul));
logger.info(String.valueOf(isRight(arrayRandom,arrayRandomCalcul)));
}
方法2:优化算法,待排数字和前面排好序列依次两两比较,标记最终位置,最后插入
private void insertSort(){
int[] arrayRandom = new int[10];
int[] arrayRandomCalcul = new int[arrayRandom.length];
Random random = new Random();
for (int i = 0; i < arrayRandom.length; i++) {
arrayRandom[i] = random.nextInt(arrayRandom.length);
}
System.arraycopy(arrayRandom, 0, arrayRandomCalcul, 0, arrayRandom.length);
logger.info(JSON.toJSONString(arrayRandomCalcul));
// int[] arrayRandomCalcul = new int[]{1,5,7,4,6};
for (int j = 1; j < arrayRandomCalcul.length; j++) {
int tmp = arrayRandomCalcul[j];
int i = j - 1;
for (; i >= 0; i--) {
if (arrayRandomCalcul[i] > tmp) arrayRandomCalcul[i + 1] = arrayRandomCalcul[i];
else break;
}
arrayRandomCalcul[i + 1] = tmp;
}
logger.info(JSON.toJSONString(arrayRandomCalcul));
logger.info(String.valueOf(isRight(arrayRandom,arrayRandomCalcul)));
}
最好情况测试:
测试目的:符合条件后是否加break对时间影响
输入:10万个已经排序好的数组
结果:
不加break:1730,1786,1805,1749
加break:0,2,0,1
测试代码:
int[] arrayRandom = new int[100000];
int[] arrayRandomCalcul = new int[arrayRandom.length];
Random random = new Random();
for (int i = 0; i < arrayRandom.length; i++) {
arrayRandom[i] = random.nextInt(arrayRandom.length);
}
System.arraycopy(arrayRandom, 0, arrayRandomCalcul, 0, arrayRandom.length);
Arrays.sort(arrayRandomCalcul);
long startTime = System.currentTimeMillis();
for (int i=1;i<arrayRandomCalcul.length;i++){//i=1执行1次,i<len执行n+1次,i++执行n次,共2n+2次
for (int j = i;j > 0;j--){//j=i执行1次,j>0执行i+1次,j--执行i次,共2i+2次
if (arrayRandomCalcul[j] < arrayRandomCalcul[j-1])swap(arrayRandomCalcul,j,j-1);//执行3次
else break;//加了break会在不满足条件下及时退出,减少程序程序指令执行次数
}
}
logger.info("运行时间"+String.valueOf(System.currentTimeMillis() - startTime));