简单算法之插入排序及其优化shell排序

1>插入排序:顾名思义是通过不断把新的元素插入到前面有序的序列中。
思路:1.当数组只有一个元素时,不需要排序。所以插入排序从a[1]开始;
2.当数组长度为n时,那么所要插入的元素a[1]~a[n-1],这利用for循环遍历所有需要被插入的元素
3.当a[i]小于a[i-1],那么a[i]就需要往前插入,以使得a[0-i]数组有序,而且a[i]是有可能小于
i-2,i-3,….,0,所以要一直往前比较插入。那么就必须把a[i]存放在一个临时变量中,这相当于在
在a[i]上挖了一个坑(快速排序中就利用了这种方法:挖坑),不断的把前面有序的元素往后移,直到刚好比a[i]大的元素,移了一位,留下了一个坑,最后把存放在临时变量里的原a[i]存放进去。就实现了
a[0-i]有序。

这是在一本书上看到的排序代码
void InsertSort(int a[],int len){
    for(int i=1;i<len;i++){
        if(a[i]<a[i-1]){        //如果后面的数小于前面的数,那就需要插入
            int temp=a[i];    //挖坑
            for(int j=i-1;j>=0 && a[j]>temp;j--)
                a[j+1]=a[j];
            a[j+1]=temp;
        }
    }
}
我觉得这个方法不是很好,一开始我看了半天,没理解。下面是我自己写的
void InsertSort1(int a[],int len){
    for(int i=1;i<len;i++){
        int temp=key;             //依旧是挖坑。
        int j=i;
        while(j-1>=0 && key<arr[j-1]){      
            arr[j]=arr[j-1];    //依次往前填坑,并形成新的坑
            j--;                      
        }
        arr[j]=temp;         //填上最后一个坑
    }
}
对比于上面的代码,我少了一个if的判断,但是我觉得那个判断是多余的,因为后面的循环中你还是会判断一遍。
可能那样效率高一点,但是对于总体的时间复杂度来说,应该没多大区别。希望有大神指导一下。

2>插入排序的时间复杂度是o(n^2),既要比较又要移动,但是如果数组本身是有序的那么他的时间复杂度为
o(n),只需要遍历一遍数组就好了。所以基于以上,我们要尽量在数组有序的时候使用插入排序。而shell排序正是居于以上思想提出的对插入排序的一种优化排序算法。

shell排序:通过把序列按一定增量分成若干个子序列,并对每个子序列进行插入排序。
一般这个增量是n/2,元素为n个。
原理是这样的:例如一个数组
12,11,3,25,2,13 按照增量6/2来划分,分成三组
12 25
11 2
3 13
再按照增量3/2划分,分成一组,那么就直接进行插入排序。

代码实现如下
public void ShellSort(){
    int[] arr={12,11,3,25,2,13,17,4,19,2};
    for(int gap=arr.length/2;gap>0;gap/=2){      //改变增量,直至增量为1
        for(int i=0;i<gap;i++){           //根据增量分成了多少组
            for(int j=i+gap;j<arr.length;j+=gap){      //对每一组进行插入排序
                int temp=arr[j];
                while(j-gap>0 && arr[j-gap]>temp){     
                    arr[j]=arr[j-gap];
                    j-=gap;
                ]
                arr[j]=temp;
            }
        }

    }
}
//要逻辑清楚,第一步要改变增量。第二步要遍历根据增量分成的每一个组。第三步要对每一组进行插入排序。这里不再是向前移一位比较了,而是向前移gap个位置来比较。

shell排序之所以效率高,是因为把数组分成了多个序列,开始进行插入排序的组数虽然多,但元素少,后面进行插入排序元素多,但已经快要趋近于有序了。所以这样比直接用插入排序效率要高很多。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值