数据结构/排序/希尔排序 --- 逻辑讲解、代码实现、图形展示

一、总体逻辑:

        1.  分组

        2. 遍历每个组的元素

        3. 组中进行插入排序(插入不会的去看我上一篇文章)

        4. 再分组

        5. 再遍历每个组的元素

        6. 再组中进行插入排序(插入还不会的再去看我上一篇文章)

        7. 再再分组

        8. 再再遍历每个组的元素

        9. 再再组中进行插入排序(插入还不会的再再去看我上一篇文章)

        .......此处省略一万字......

        n. 再再再再再分组

        n+1. 再再再再再再遍历每个组的元素

        n+2. 再再再再再再组中进行插入排序(插入还不会的再再再再再再再再去看我上一篇文章)        

        完了,不认识 “再” 这个字了。

        废话不多说,上解释!

二、解释:

        1. 有关分组:有关数据增量的问题......我不会,好吧其实是数学里改涉及的,咱们计算机学生就无需过多涉及了,这里只提供两种分组方式:

                一种是:根据间隔的空隙分,即每隔 len / 2 - 1 个空隙 为同一组

                二种是:根据间隔的空隙分,即每隔 len / 2 个空隙 为一组

        注意,这里说的分组不是划分区域,而是每一组元素不相连,上图!(相同颜色的为一组)

        然后一直分下去,直到都分为一组

        2. 然后进行遍历每个组中的每个元素,很显然,一个每对应一个for循环

        3. 最后在组中进行插入排序

很nice!,你现在已经会了八成了


三、接着就是循环:

        1. 是不是每次都要分组?

        啥?你说不是?比方说第二种分组方式,假设一共8个元素,第一次分组是 8 / 2 = 4 ,是不是每隔 4 个空隙分一组。第二次分组就是 4 / 2 = 2,是不是每隔 2 个空隙分一组。第三次分组就是 2 / 2 = 1,是不是每隔 1 个空隙分一组……

        SO,是不是每次都要分组?当然是啦

        所以最最最外层的循环就是每次分组间隔为一半,即group第一次为第一次分组的结果4,然后group每次为之前的一半,直到 group = 1

for (int group = len / 2; group > 0; group /= 2)

        2. 是不是要遍历每个组中的元素前,要遍历每个组?当然是啦!

        所以最最外层的循环就是遍历每个组

for (int i = 0; i < group; i++)

        3. 是不是要遍历每个组中的元素?当然是啦!因为分组的条件是动态的,所以元素个数也是动态的,即是数组长度 / 分组间隔 = 每组元素个数,懵了?

        再解释解释,就是假设 8 个元素

for (int j = 0; j < len / group; j++)

                第一次分组:8 / 2 = 4,每个组元素个数为几?当然是 2 呀

                第二次分组: 4 / 2 = 2,每个组元素个数为几?当然是 4 呀

                第三次分组: 2 / 2 = 1,每个组元素个数为几?当然是 8 呀

                ……

                有没有发现什么规律?

        4. 然后就是每个组的元素内进行插入排序,由于前面把变量 i 和 j 用了,这里用 m 代替上一篇文章中的索引 j ,道理都是一样的

四、代码附上:

#include <stdio.h>

void printArr(int *arr, int len)
{
  for (int i = 0; i < len; i++)
    printf("%d ", arr[i]);
  printf("\n");
}

//               1  2  3  4  1  2  3  4     8 / 2 = 4
//               1  2  1  2  1  2  1  2     4 / 2 = 2
//               1  1  1  1  1  1  1  1     2 / 2 = 1
// int arr1[] = {5, 6, 2, 8, 7, 3, 1, 4};
void shellSort_circulation(int *arr, int len)
{
  int groupSign;
  // 每次分组间隔为一半
  for (int group = len / 2; group > 0; group /= 2)
  {
    // 遍历每个组
    for (int i = 0; i < group; i++)
    {
      // 遍历每个组中的元素
      for (int j = 0; j < len / group; j++)
      {
        // 记录待排元素
        int key;
        // 索引
        int m;
        for (int k = group; k < len / group; k++)
        {
          // 取出待排元素
          key = arr[k];
          // 记录有序元素中的最后一个
           m= k - 1;
          // 将有序部分中的大于待排元素的元素后移一位
          while (m >= 0 && arr[m] > key)
          {
            arr[m + 1] = arr[m];
            m--;
          }
          // 插入待排元素
          arr[m + 1] = key;
        }
      }
    }
  }
}

void main()
{
  int arr1[] = {5, 6, 2, 8, 7, 3, 1, 4};
  printf("排序前:\n");
  printArr(arr1, sizeof(arr1) / sizeof(int));
  shellSort_circulation(arr1, sizeof(arr1) / sizeof(int));
  printf("排序后:\n");
  printArr(arr1, sizeof(arr1) / sizeof(int));
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值