八大排序之希尔排序

希尔排序基本介绍

希尔排序是希尔(Donald Shell) 于 1959 年提出的一种排序算法。 希尔排序也是一种插入排序, 它是简单插入排序经过改进之后的一个更高效的版本, 也称为缩小增量排序。

希尔排序基本思想

希尔排序按照增量将数组进行分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止.

希尔排序图解(交换法)

第一次:gap = arr.length/5 = 5 , 将数组分为五组,每个数组元素的索引相差 5

如何完成第一次的排序?

仔细想想,我们需要用一次循环将每组中的元素排序

总共有五组,我们又需要一次循环

所以完成每次排序,需要两层循环

程序代码如下,把 i ,j 都看作是辅助指针:

i 与 j 配合使用,可以将指针从数组第一个元素,移动至最后一个元素,目的:把数组遍历一遍

j 与 i 配合使用,每次都从数组索引 i 处往前遍历,每次向前移动 gap 个位置,然后进行交换(冒泡排序的意思):看看前面的元素有没有比我的值大,如果前面的元素比我的值大,我就要和他交换位置,跑到前面去.

第二次:gap = gap /2 = 2; , 将数组分为两组,每个数组元素的索引相差 2

第一组:

i = 2 时,数组从索引 2 处往前遍历,间隔为 2 :将 arr[0]、arr[2] 排序

i = 4 时,数组从索引 4 处往前遍历,间隔为 2 :将 arr[0]、arr[2]、arr[4] 排序

i = 6 时,数组从索引 6 处往前遍历,间隔为 2 :将 arr[0]、arr[2]、arr[4]、arr[6] 排序

i = 8 时,数组从索引 8 处往前遍历,间隔为 2 :将 arr[0]、arr[2]、arr[4]、arr[6]、arr[8] 排序

第二组:

i = 3 时,数组从索引 3 处往前遍历,间隔为 2 :将 arr[1]、arr[3] 排序

i = 5 时,数组从索引 5 处往前遍历,间隔为 2 :将 arr[1]、arr[3]、arr[5] 排序

i = 7 时,数组从索引 7 处往前遍历,间隔为 2 :将 arr[1]、arr[3]、arr[5]、arr[7] 排序

i = 9 时,数组从索引 9 处往前遍历,间隔为 2 :将 arr[1]、arr[3]、arr[5]、arr[7]、arr[9] 排序

第三次:gap = gap /2 = 1; , 将数组分为一组,每个数组元素的索引相差 1 ,对于交换法而言,这就是异常冒泡排序

i = 1 时,数组从索引 1 处往前遍历,间隔为 1 :将 arr[0]、arr[1] 排序

i = 2 时,数组从索引 2 处往前遍历,间隔为 1 :将 arr[0]、arr[1]、arr[2] 排序

i = 3 时,数组从索引 3 处往前遍历,间隔为 1 :将 arr[0]、arr[1]、arr[2]、arr[3] 排序

总结:每次使用循环改变 gap 的值(初始值:数组大小/2 ,之后:gap = gap/2),然后在改变 gap 的循环中嵌套上面的双层 for 循环.

改变 gap :for (int gap = arr.length / 2; gap > 0; gap /= 2) {

内层循环:实现对每组数组的排序.

代码如下:

    public static void shellSort(int[] arr) {
        // 增量gap, 并逐步的缩小增量
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            // 从第gap个元素,逐个对其所在的组进行直接插入排序
            for (int i = gap; i < arr.length; i++) {
                int j = i;
                int temp = arr[j];
                if (arr[j] < arr[j - gap]) {
                    while (j - gap >= 0 && temp < arr[j - gap]) {
                        // 移动
                        arr[j] = arr[j - gap];
                        j -= gap;
                    }
                    // temp 比 arr[j - gap] 大,所以需要插入在 j 的位置
                    arr[j] = temp;
                }

            }
        }
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值