插入类排序

一、基本思想

在一个已排好序的记录子集的基础上,每一步将下一个待排序的记录有序插入到已排好序的记录子集中,直到将所有待排记录全部插入为止。例如:打扑克牌。

二、直接插入排序(升序)

思想:在有序部分,查找合适的位置。

查找方法:遍历查找(遍历又分为从后往前和从前往后)和二分查找。

适用场景:在待排序的关键字序列基本有序且关键字个数n较少时,其算法性能最佳。

1.遍历查找

将第i个记录插入到前面i-1个已排好序的记录中。 通常我们会在i-1个排好序的序列中从后往前遍历,直到找到比它小的数,并将第i个数插入到该数后面。

public class InsertSort {
    //直接插入排序(升序)
    //思路:遍历每一个元素,将下标为i的元素插入到前面有序的数组中。插入的位置需要从后往前遍历,直到找到比它小的数,插入到比它小的数的后面
    //移动的元素下标范围:[j+1,i-1]-->[j,i]  从后往前搬移  优化:边遍历边搬移
    //有序:[0,i)  无序:[i,array.length-1]
    private static void insertSort(int[] array){
        for(int i=0;i<array.length;i++){
            int key=array[i];//记录
            int j=i-1;
            for(;j>=0;j--){
                if(key<array[j]){
                    array[j+1]=array[j];
                }else{
                    break;
                }
            }
            array[j+1]=key;//插入array[i]
        }
    }

    public static void main(String[] args) {
        int[] array=new int[]{34,23,49,3,45,100,324};
        insertSort(array);
        for(int item:array){
            System.out.print(item+" ");
        }
    }
}

2.二分查找

public class InsertSort {
//左闭右开形式查找
       private static void binInsertSort(int[] array){
        //遍历每一个数,在已排好序的序列中[0,i]找到合适的插入位置
        for(int i=0;i<array.length;i++){
            int key=array[i];
            int left=0;
            int right=i;
            while(left<right){//==时,区间没有一个数据
                int mid=left+(right-left)/2;
                if(array[mid]==key){
                    left=mid+1;
                }else if(array[mid]>key){
                    right=mid;//右开
                }else{
                    left=mid+1;
                }
            }
            //left就是要插入的位置
            //搬移数据[left,i)
            for(int p=i;p>left;p--){
                array[p]=array[p-1];
            }
            array[left]=key;
        }
    }
//左闭右闭形式查找
    private static void binInsertSort2(int[] array){
        for(int i=0;i<array.length;i++){
            int key=array[i];
            int left=0;
            int right=i-1;//左闭右闭
            while(left<=right){
                int mid=left+(right-left)/2;
                if(array[mid]==key){
                    left=left+1;
                }else if(array[mid]>key){
                    right=mid-1;
                }else{
                    left=left+1;
                }
            }
            //left就是要插入的位置  将[left,i-1]的数据搬移到[left+1,i]的位置上
            for(int p=i;p>left;p--){
                array[p]=array[p-1];
            }
            array[left]=key;
        }
    }
    public static void main(String[] args) {
        int[] array=new int[]{34,23,49,3,45,100,324};
        binInsertSort(array);
        for(int item:array){
            System.out.print(item+" ");
        }
        System.out.println();
        binInsertSort2(array);
        for(int item:array){
            System.out.print(item+" ");
        }
    }
}

3.时间复杂度、空间复杂度和稳定性分析

直接插入排序(遍历查找):

时间复杂度:最好:O(n)     最坏:O(n^2)      平均:O(n^2)

空间复杂度:O(1)

稳定性:稳定

直接插入排序(二分查找):

时间复杂度: 最好:O(n)    最坏:O(n^2)   平均:O(n*log(n))

空间复杂度:O(1)

稳定性:稳定

二、希尔排序

1.思想:利用直接插入排序的最佳性质,首先,将待排序的关键字序列分成若干个较小的子序列,对子序列进行直接插入排序,使整个待排序序列排好序(预排序)。最后,再对整体进行直接插入排序。

如何分组?一般令gap=length,令gap=(gap/3)+1或者gap=gap/2.

public class InsertSort {
    //希尔排序
    private static void shellSort(int[] array){
        int gap=array.length;
        while(gap>0){
            for(int i=0;i<gap;i++) {
                //分组
                shellinsertSort(array, i,gap);
            }
            gap=gap/2;
        }
    }
    private static void shellinsertSort(int[] array,int begin,int gap){
        for(int i=begin;i<array.length;i+=gap){
            //遍历每个已排好序的数[begin,begin+gap,...i)
            int key=array[i];
            int j=i-gap;
            for(;j>=begin;j-=gap){
                if(key<array[j]){
                    array[j+gap]=array[j];
                }else{
                    break;
                }
            }
            array[j+gap]=key;
        }
    }
    public static void main(String[] args) {
        int[] array=new int[]{34,23,49,3,45,100,324};
        binInsertSort(array);
        for(int item:array){
            System.out.print(item+" ");
        }
        System.out.println();
        binInsertSort2(array);
        for(int item:array){
            System.out.print(item+" ");
        }
        System.out.println();
        shellSort(array);
        for(int item:array){
            System.out.print(item+" ");
        }

    }
}

希尔排序的时间复杂度、空间复杂度和稳定性分析

时间复杂度:最好:O(n)   最坏:O(n^2)  平均:O(n^1.2-1.5)(百科上写的是O(n^1.3-2)

空间复杂度:O(1)

稳定性:不稳定(因为不能保证相同数值的数被分到同一组中)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值