• 排序算法 —— 希尔排序(图文超详细)



    排序算法:

    1、直接插入排序

    2、选择排序

    3、堆排序

    希尔排序(直接插入排序的优化)

    希尔排序是将数据分组,将每一组进行插入排序。
    每一组排成有序后,最后整体就变有序了。

    1.分组思想


    上图中gap为5,说明要分成5组。
    这5组分别用了五种颜色的线条连接起来了。

    第1组:9、4
    第2组:1、8
    第3组:2、6
    第4组:5、3
    第5组:7、5

    为什么要采取上面的分组方法呢?换一种方法可以吗?
    例如:挨着的元素分为一组。


    如果是上面的这种分组方式的话,排序之后会变成下面的情况。



    如果是最开始的分组方法的话

    如果是按照最开始的分组思想分组的话,最后会排序成

    可以发现左边都是叫小的数据,右边都是较大的数据。
    更方便把分成的每一个组进行插入排序。

    2.缩小增量的过程

    前面gap为5的情况排序后会变成下面情况


    按照gap把数据分成了两组。

    当数据很大的时候,数据的间隔很大。
    小的数据会往前方,大的数据会往后放。

    gap会逐渐缩小,间隔也会逐渐缩小。

    整体的数据会更加趋于有序,这个时候使用直接插入排序效率会更高。



    gap为2的时候会排序成下面情况

    此时分为了1组,再排序一次后变成下面情况

    此时的数据即为有序的。

    3.排序步骤

    3.1 排序五组数据的情况

    1. gap为5,将数据分为5组,图中红色线画中的为第一组。定义一个 i 变量指向这一组的第二个数据,定义一个 j 变量指向 i - gap 的位置。
    2. 将 i 下标的值放到定义的 tmp 中,然后与 j下标 的值比较。
      若 j 下标的值较大,将 j 下标的值放到 j + gap 的位置。

      执行后:
    3. j 变量向 j - gap 位置走,若这个位置的下标为负数。
      则要将 tmp 的值放到 j + gap的位置。

      j 变量此时在-5下标处,要将 tmp 的值放到 j + 5的位置。

      这一组数据此时为有序了。
      排序下一组数据,**i++**即可,j 变量依然是在 i - gap 的位置。
      后面4组数据类似,不在演示。
      最终排序结果是:

    3.2 排序两组数据的情况

    1. 此时 gap 为2,数据此时分为了两组。第一组由红色线画出(4、2、5、8、5),第二组由蓝色线画出(1、3、9、6、7)。
      i 变量指向这一组的第二个数据, j 变量指向 i - gap 的位置。

    2. 将 i 下标的值放到定义的 tmp 中,然后与 j下标 的值比较。
      若 j 下标的值较大,将 j 下标的值放到 j + gap 的位置。

      执行后:

    3. j 变量向 j - gap 位置走,若这个位置的下标为负数。
      则要将 tmp 的值放到 j + gap的位置。

      j 变量此时在-2下标处,要将 tmp 的值放到 j + 2的位置。

      这一组数据中的 2 和 4 此时为有序了。
      排序下一组数据,i++ 即可,j 变量依然是在 i - gap 的位置。
      后面剩下的数据类似,不在演示。
      最终排序结果是:

    3.3 排序一组数据的情况

    1. i 变量指向第二个数据, j 变量指向 i - gap 的位置。
    2. 将 i 下标的值放到定义的 tmp 中,然后与 j下标 的值比较。
      若 j 下标的值较大,将 j 下标的值放到 j + gap 的位置。

      执行后:
    3. j 变量向 j - gap 位置走,若这个位置的下标为负数。
      则要将 tmp 的值放到 j + gap的位置。

      j 变量此时在-1下标处,要将 tmp 的值放到 j + 1的位置。

      此时 前两个数据有序了,后面的数据排序过程类似。
      排序下一组数据,i++ 即可,j 变量依然是在 i - gap 的位置。
      最终结果是:

    4.代码分析

    4.1 如何设置数据组数

    1. 定义 gap 将数组的长度赋值给这个变量。
    int gap = array2.length;//为数组的长度 - 为10
    
    • 1
    1. 设置循环,每次使 gap 除以2来得到5、2、1三个组。
    2. 在循环内部调用直接插入排序方法。
     while (gap > 1) {
         gap /= 2;//先是分成了5组,然后是2组,再是1组
         shell(array2, gap);//调用直接插入排序方法
     }
    
    • 1
    • 2
    • 3
    • 4

    4.2 直接插入排序实现思路

    1. 遍历数组,i 变量从 gap 下标位置开始
    for (int i = gap; i < array2.length ; i++){
    }
    
    • 1
    • 2
    1. j 变量从 i- gap 位置开始
      int j = i - gap;
    
    • 1
    1. j 变量要每次减去 gap 个位置,j 此时的位置要是负数就比较 j 和 tmp 的值。
    for (; j >= 0; j-=gap){
    }
    
    • 1
    • 2
    1. j 和 tmp 如何比较
     if (array2[j] > tmp) {
         //j下标的值大,将j下标的值放到j变量加上一个gap的位置上
         array2[j + gap] = array2[j];
     }else {
         //j下标的值较小,j下标的值要直接放到j变量加上一个gap的位置上
         break;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. j 下标为负数的情况
     //此时j下标的值是负数了,将tmp的值放到j变量加上一个gap的位置上
     array2[j + gap] = tmp;
    
    • 1
    • 2

    更加详细的直接插入排序讲解请参考我的另一篇文章。


    文章链接:http://t.csdn.cn/rBDzh

    5. 整体代码实现

     public static void shellSort(int[] array2) {
         int gap = array2.length;//为数组的长度 - 为10
         while (gap > 1) {
             gap /= 2;//先是分成了5组,然后是2组,再是1组
             shell(array2, gap);//调用直接插入排序方法
         }
     }
    
     //实现直接插入排序方法
     public static void shell(int[] array2, int gap) {
         //i下标从第一组的第二个数据开始
         for (int i = gap; i < array2.length ; i++) {
             int tmp = array2[i];//tmp存放i下标的值
             int j = i - gap;//j下标为i-gap个位置
             //j每次-gap个位置
             for (; j >= 0; j-=gap) {
                  if (array2[j] > tmp) {
                    //j下标的值大,将j下标的值放到j变量加上一个gap的位置上
                    array2[j + gap] = array2[j];
                  }else {
                     //j下标的值较小,j下标的值要直接放到j变量加上一个gap的位置上
                     break;
                  }
              }
              //此时j下标的值是负数了,将tmp的值放到j变量加上一个gap的位置上
              array2[j + gap] = tmp;
          }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

  • 相关阅读:
    20条心灵鸡汤唯美句子,句句温情暖心!
    Loading class `com.mysql.jdbc.Driver‘. This is deprecated.
    mysql快问快答(1)---MySQL常用的存储引擎MyISAM和InnoDB
    计算机组成原理期末复习(二)
    22noip10连 day7--考后总结
    90.STL-谓词的使用
    InnoDB 存储引擎之 Buffer Pool
    【uni-app】申请高德地图key,封装map.js,实现H5、iOS、Android通过getlocation获取地图定位信息
    在linux上部署一个web项目的小经验
    tp5微信公众号开发,申请公众号配置token验证
  • 原文地址:https://blog.csdn.net/m0_63033419/article/details/127524644