希尔排序分析实现

算法思想:

希尔排序又叫缩小增量,也是一种插入排序。希尔排序中有一个步长,通过这个步长将数组分化为步长个序列,然后分别对这些序列进行直接插入排序,然后改变步长,重复操作,直到步长为1,而此时数组基本有序,很快。步长的取法一般是开始为(数组长度/2),然后是对步长一直除2直到步长为1。

算法运行过程图:

这里写图片描述

代码实现思路:
  • 思路1:按照算法思想,有一个循环步长的循环,然后对某个步长划分的那些子序列进行插入排序。
  • 思路2:相对于上面的每次直接插入排序从序列的第一个元素开始,直到该序列的最后一个元素,其实直接插入排序时可以从下标为步长的元素开始,然后相当于混合这对划分的每个序列进行直接排序,直接排序其实是从序列的第2个元素开始,然后每次判断是否比该序列的前一个数小,如果小的话就进行插入操作。见shellSort1()注释。

优化方法:

  1. 优化步长。有点麻烦。
  2. 优化直接插入排序。见shellSort()注释。
时间复杂度:

根据步长的不同取法不一定。有点复杂。

空间复杂度:

O(1)

稳定性:

不稳定。
在子序列的插入过程中可能打乱稳定性。

代码实现:
package sort;

/**
 * @作者:dhc
 * @创建时间:20:41 2018/8/14
 * @排序方法:希尔排序
 * @时间复杂度:有点复杂。
 * @空间复杂度:O(1)
 * @稳定性:不稳定。
 */
public class ShellSort {
    /**
     * 直接插入排序说明:这里直接插入排序因为有几种不同的写法,1,常规的先找插入位置,在后移 插入。2,对1插入位置查找采用二分查找。3,不用先查找
     * 位置,将两个循环合成一个,直接后移。4,同3一样,用一个循环,不过用交换来实现。因此希尔排序也可有对应的写法。采用不同的写法,对于希尔排序的结果
     * 也稍有点点优化。
     * 步长说明:取数组长度的一半,然后循环取一半直到步长为1.
     * @param nums
     */
    public static void shellSort(int[] nums) {
        int tem = 0;
        for(int ss = nums.length/2;ss >= 1; ss /= 2){
            for (int k = 0; k < ss; k++) {
                //直接插入排序
                for(int i = ss;i < nums.length;i += ss){
                    tem = nums[i];
                    int j = i;
                    for(j = i;j > 0 && nums[j - ss] > tem;j -= ss){
                        nums[j] = nums[j-ss];
                    }
                    nums[j] = tem;
                }
            }
        }
    }

    /**
     * 优化循环次数
     * 相对于上面的每次直接插入排序从序列的第一个元素开始,直到该序列的最后一个元素,其实可以直接插入排序时可以从下标为步长的元素开始,然后
     * 相当于混合这对划分的每个序列进行直接排序,直接排序其实是从序列的第2个元素开始,然后每次判断是否比该序列的前一个数小,如果小的话就进行
     * 插入操作。
     * @param nums
     */
    public static void shellSort1(int[] nums) {
        int tem = 0;
        for(int ss = nums.length/2;ss >= 1; ss /= 2){
            //这里取i等于步长,相当于直接进入插入排序,用划分的第一个序列的第二个元素开始,当i+1时,如不步长不为1,则相当于
            // 进入下一个序列的插入排序,这个i+1同样是第二个元素,直到i+ss,有进入第一个序列的第三个数,循环往复,直到数组最后
            for (int i = ss; i < nums.length; i++) {
                //这里判断是否比该序列的前一个数小,如果小的话就要插入到该序列的前面
                if(nums[i] < nums[i - ss]){
                    tem = nums[i];
                    int j = i;
                    for(j = i - ss;j >=0 && nums[j] > tem;j-=ss){
                        nums[j+ss] = nums[j];
                    }
                    nums[j + ss] = tem;
                }
            }
        }
    }
    public static void main(String[] args) {
        int[] nums = new int[]{5,4,3,2,1,1,7,6};
        shellSort1(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i]+" ");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值