插入排序优化算法

特点:样本小且基本有序情况下效率高,并且稳定。

选择排序、冒泡排序、插入排序区别:

  • 选择排序,每次选择最大/小值放到前面合适位置,每轮内层循环交换一次。排好的子数组有序。
  • 冒泡排序,每次两两比较都交换,将最大/小值交换到子数组位置。排好子数组有序。
  • 插入排序,每次插入后子数组都有序,且不是根据最大/最小值排序。

思路 :前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));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值