排序-插入排序

插入排序


public class Insertion {
    private static boolean less(Comparable v,Comparable w){
        return v.compareTo(w)<0;
    }
    private static void exch(Comparable[] a,int vIndex,int wIndex){
        Comparable temp = a[vIndex];
        a[vIndex] = a[wIndex];
        a[wIndex] = temp;
    }
    private static void show(Comparable[] a){
        for(int i=0,len=a.length;i<len;i++)
            StdOut.print(a[i]+" ");
        StdOut.println();
    }
    private static boolean isSorted(Comparable[] a){
        for(int i=1,len=a.length;i<len;i++)
            if(less(a[i],a[i-1])) return false;
        return true;
    }
    public static void sort(Comparable[] a){
        int N = a.length;
        for(int i=1;i<N;i++)
            for(int j=i;j>0&&less(a[j],a[j-1]);j--)
                exch(a,j,j-1);
    }
    public static void main(String[] args){
        String[] a = new In(args[0]).readAllStrings();
        sort(a);
        assert isSorted(a);
        show(a);
    }
}

实现策略

类似于打扑克牌拿牌的时候,手上的牌是已经有序的,现在拿上一张牌,对应数组中下一个元素,找到相应的位置进行插入,假设已经有序则,不需要进行交换

分析

与输入有关,假设已经有序则不会进行交换操作,整体运行时间在线性范围,适合处理那些存在一些顺序的排序。倒置是值排序后的元素与排序前的相对位置发生改变的情况,发生倒置的数量越少使用插入排序效率越高(遍历数组交换的数量越少)。最好情况下N-1次比较,0次交换,最差情况下(每次拿的新牌都是当前手中最小的,需要将其遍历整个数组放在最开始),需 要1+2+…N-1~N²/2次比较和N²/2次交换(第一次交换一个,第二次移动两个元素位置…),平均为N²/4次比较和N²/4次交换。

改进

可以不用每次都进行交换操作,改进策略可以先将较大的元素向后移动,找到真正的位置后进行插入操作,如下,一些注意在注释中给出。

 public static void sortHalfExchange(Comparable[] a){
        int N = a.length;
        int exchanges = 0;
        // 先找出最小值作为哨兵,以防超出范围
        for(int i=N-1;i>0;i--){
            if(less(a[i],a[i-1])){
                exch(a,i,i-1);
                exchanges++;
            }
        }
        if(exchanges==0) return;

        for(int i=2;i<N;i++){
            Comparable v = a[i];// 当前插入的值
            int j=i;
            // 上一步保证了a[0]一定是最小的,不会出现超出ArrayIndexOutOfBoundsException的风险
            while (less(v,a[j-1])){
                a[j] = a[j-1];// 较大的值向后移动
                j--;
            }
            a[j] = v;// 在插入位置插入值
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值