一、总体逻辑:
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));
}