【算法】【排序算法】【02】插入排序&二分搜索

插入排序核心思想:
在这里插入图片描述
将无序区域的第一个元素 插入到有序区域中属于自己的位置

1. 交换插排

public class _04_Insert<T extends Comparable<T>> extends Sort<T> {


    @Override
    protected void sort() {
        for (int end = 1; end < array.length; end++) {
           for(int i = end;i>0;i--){
               if(cmp(array[i],array[i-1])<0){
                   swap(i,i-1);
               }else{
                   break;
               }
           }
        }
    }

}
【_03_HeapSort】
稳定性:false 	耗时:0.011s(11ms) 	比较:51.06万	 交换:2.00------------------------------------------------------------------
【_02_Select】
稳定性:true 	耗时:0.396s(396ms) 	比较:2.00亿	 交换:2.00------------------------------------------------------------------
【_04_Insert】
稳定性:true 	耗时:0.425s(425ms) 	比较:1.00亿	 交换:1.00亿
------------------------------------------------------------------
【_01_Bubble】
稳定性:true 	耗时:1.281s(1281ms) 	比较:2.00亿	 交换:1.00亿
------------------------------------------------------------------
【_01_Bubble_3】
稳定性:true 	耗时:1.848s(1848ms) 	比较:2.00亿	 交换:1.00亿
------------------------------------------------------------------
【_01_Bubble_2】
稳定性:true 	耗时:1.85s(1850ms) 	比较:2.00亿	 交换:1.00亿
------------------------------------------------------------------

2.挪动插排

public class _04_Insert2<T extends Comparable<T>>  extends Sort<T> {

    //不挨个交换,找到目标位置index 将(index,end)的元素全部后移
    @Override
    protected void sort() {
        for(int end = 1;end < array.length;end++){
            T ele = array[end];
            for(int i = end -1;i>=0;i--){
                if(cmp(array[i],ele)>0){
                    array[i+1] = array[i];
                }else{
                    //ele >= array[i]
                    array[i+1] = ele;
                    break;
                }
            }
        }
    }

}
【_03_HeapSort】
稳定性:false 	耗时:0.011s(11ms) 	比较:51.08万	 交换:2.00------------------------------------------------------------------
【_02_Select】
稳定性:true 	耗时:0.394s(394ms) 	比较:2.00亿	 交换:2.00------------------------------------------------------------------
【_04_Insert】
稳定性:true 	耗时:0.576s(576ms) 	比较:1.00亿	 交换:1.00亿
------------------------------------------------------------------
【_04_Insert2】
稳定性:true 	耗时:0.601s(601ms) 	比较:1.52亿	 交换:0
------------------------------------------------------------------
【_01_Bubble】
稳定性:true 	耗时:1.292s(1292ms) 	比较:2.00亿	 交换:1.00亿
------------------------------------------------------------------
【_01_Bubble_3】
稳定性:true 	耗时:1.832s(1832ms) 	比较:2.00亿	 交换:1.00亿
------------------------------------------------------------------
【_01_Bubble_2】
稳定性:true 	耗时:1.856s(1856ms) 	比较:2.00亿	 交换:1.00亿
------------------------------------------------------------------

3. 二分搜索

二分搜索的前提是有序序列;只有有序序列才能够使用二分搜索

  • 如果是无序数组,从第 0 个位置开始遍历搜索,平均时间复杂度:O(n)
    在这里插入图片描述
  • 如果是有序数组,可以使用二分搜索,最坏时间复杂度:O(logn)
    在这里插入图片描述

3.1 递归实现 查找目标数据应插入的位置


public class _05_BinarySearch {

   //此二分搜索方法用于寻找V在有序数组中的索引位置

    //todo 1.递归实现
    public static int search(int[] array, int v){
        if(array == null || array.length == 0) return -1;
        return search(array,v,0,array.length-1);
    }
    private static int search(int[] array,int v,int low,int high){
        int mid = (low+high)>>1;

        if(mid == high){
            if(array[low] <= v){
                return low+1;
            }else{
                return low;
            }
        }

        if(array[mid] > v){
            return search(array,v,low,mid-1);
        }else if(array[mid] < v){
            return search(array,v,mid+1,high);
        }else {
            return mid;
        }
    }
}

递归终止条件:mid == high,不能写low == high
low == high 只包含这一种情况
mid == high 包含 low == highhigh == low -1
mid == low 包含 low == highlow == high -1

当low == high -1的时候,mid == low,所以其实是在比较array[low]和goal的关系:

  • 如果array[low] < goal ,那么low + 1,此时low == high,此时用low == high没问题;
  • 如果array[low] > goal ,high = mid -1 也就是high = low -1,此时已经交叉了:mid = (low - 1 + low) /2 = low -1 ,所以按照mid == high 做终止条件!

简而言之:要么在low == high处终止,要么在 low = high - 1处终止;那么这两种情况都可以用 mid == high来概括

3.1 迭代实现 查找目标数据应插入的位置

//    todo 2.迭代实现
    public static int search2(int[] array, int v){
        if(array == null || array.length == 0) return -1;
        int high = array.length-1;
        int low = 0;
        int mid;
        while(high > low){
            mid  = (high + low )>>1;
            if(array[mid] == v){
                return mid;
            }else if(array[mid] > v){
                high = mid - 1; //high = low 那么 low位置<V
            }else{
                low = mid + 1;  //high = low 那么 low位置>V
            }
        }
        //到这里说明 high = low
        if(array[low] >= v){
            return low;
        }else{
            return low+1;
        }
    }

4. 挪动插排 + 二分搜索

ublic class _07_Insert_BinarySearch<T extends Comparable<T>> extends Sort<T> {

    private int searchIndex(T[]array,T v){
        return searchIndex(array,v,0,array.length-1);
    }


    private int searchIndex(T[] array,T v,int low,int high){
        if(array == null || array.length == 0) return -1;

        int mid;
        while(high > low){
            mid  = (high + low )>>1;
            if(array[mid] == v){
                return mid;
            }else if(cmp(array[mid] ,v)>0){
                high = mid - 1;
            }else{
                low = mid + 1;
            }
        }
        //到这里说明 high = low
        if(cmp(array[low],v)>0){  //如果这里改为>= 就不是稳定排序了
            return low;
        }else{
            return low+1;
        }
    }

    @Override
    protected void sort() {
        for (int i = 1; i < array.length; i++) {
            //[0,i)是有序区域    arr[i] 是待插元素
            T tmp = array[i];
            int insertIndex = searchIndex(array, tmp,0,i-1);  //logN
            //将[insertIndex,i-1]范围内的有序元素 往后移动1位
            for(int j = i;j>insertIndex;j--){
                array[j] = array[j-1];
            }//n
            //将元素插进去
            array[insertIndex] = tmp;
        }
    }
    // n*(n+logN) => 因此时间复杂度还是O(n平方)  只不过优化了搜索 索引的位置
}
【_03_HeapSort】
稳定性:false 	耗时:0.012s(12ms) 	比较:51.06万	 交换:2.00------------------------------------------------------------------
【_07_Insert_BinarySearch】
稳定性:true 	耗时:0.291s(291ms) 	比较:26.09万	 交换:0
------------------------------------------------------------------
【_02_Select】
稳定性:true 	耗时:0.394s(394ms) 	比较:2.00亿	 交换:2.00------------------------------------------------------------------
【_04_Insert】
稳定性:true 	耗时:0.572s(572ms) 	比较:9977.75万	 交换:9975.75------------------------------------------------------------------
【_04_Insert2】
稳定性:true 	耗时:0.661s(661ms) 	比较:1.61亿	 交换:0
------------------------------------------------------------------
【_01_Bubble】
稳定性:true 	耗时:1.314s(1314ms) 	比较:2.00亿	 交换:9975.75------------------------------------------------------------------
【_01_Bubble_2】
稳定性:true 	耗时:1.833s(1833ms) 	比较:2.00亿	 交换:9975.75------------------------------------------------------------------
【_01_Bubble_3】
稳定性:true 	耗时:1.844s(1844ms) 	比较:2.00亿	 交换:9975.75------------------------------------------------------------------

Process finished with exit code 0

复杂度与稳定性
使用了二分搜索后,只是减少了比较次数,但插入排序的平均时间复杂度依然是 O(n2)

最坏、平均时间复杂度:O(n2)
最好时间复杂度:O(n)
空间复杂度:O(1)
属于稳定排序

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值