希尔排序(附有详细C语言代码)

希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。


其实直接插入排序并不是那么逊的,它在待排序数据基本有序并且数量较少的时候威力还是很大的,甚至比一些高级算法还要高效.对于第二点,我只能说这就是我们shell算法的牛逼的地方了,插入排序每次只能移动数据一位,而shell算法成功的解决了这个问题.


shell算法的核心还是分组,但是这个分组就有门道儿了,因为它会实现取一个小于总数据长度的整数值gap作为分组的步长,什么意思呢?假如我们的待排序数组为:

序号  1      2     3      4      5     6      7      8     9     10

49,38,65,97,76,13,27,49,55,04 

设置gap的值为长度10的一半也就是5,那么第一个和第六个元素就是一组,第二个和第七个元素就是一组,第三个和第八个元素就是一组,第四个和第九个元素就是一组,第五个和第十个元素就是一组,所以一共分为了gap = 5组,

  组     一     二    三     四        五

     序号  1    6   2    7               3    8                4      9                 5    10

     数据  49  13         38  27        65  49        97    55             76   04

  交换后   13  49               27  38             49  65              55     97               04   76

然后如上面每一组之间进行再直接插入排序,比较如果前一个元素比较大,则交换两个元素的位置,直至5组全部交换完毕.此时数组的顺序为

13   27   49   55   04    49   38   65   97   26.

然后gap的值再减半为2,重新分组,也就是第一个 第三个 第五个 第七个 第九个 元素为第一组是13  49  4  38  97, 第二个 第四个 第六个 第八个 第十个元素为一组是27  55  49  65  26.

组                     一                   二

序号 1      3      5      7      9            2      4 6 8   10

数据 13 49   04   38 97       27   55      49 65  26

交换后     04    13   38   49      97          26   27      49     55     65

     

然后如上面对它们两个组分别进行直接插入排序,得到结果为

  4   26   13   27   38    49   49   55   97   65,

之后gap的值再减半为1(要知道gap的值小于1的时候在分组就没意义了,一位你的每一个组至少要有一个元素才能组成一个序列.)这次我们直接对上一次的结果进行一次真正的直接插入排序(为什么说是真正的呢,因为此时步长已经为1)直至得出最终结果:

4   13   26   27   38    49   49   55   65   97.


下面是shell算法的实现代码:

#include <stdio.h>
#include <malloc.h>

void shellSort(int *a, int len); // 函数声明

int main(void)
{
    int i, len, * a;
    printf("请输入要排的数的个数:");
    scanf("%d",&len);
    a = (int *)malloc(len * sizeof(int)); // 动态定义数组
    printf("请输入要排的数:\n");
    for (i = 0; i < len; i++) { // 数组值的输入
        scanf("%d",&a[i]);
    }   
    shellSort(a, len); // 调用希尔排序函数
    printf("希尔升序排列后结果为:\n");
    for (i = 0; i < len; i++) { // 排序后的结果的输出
        printf("%d\t",a[i]);
    }
    printf("\n");

    return 0;
}

void shellSort(int *a, int len)
{
    int i, j, k, tmp, gap;  // gap 为步长
    for (gap = len / 2; gap > 0; gap /= 2) {  // 步长初始化为数组长度的一半,每次遍历后步长减半,
    	for (i = 0; i < gap; ++i) { // 变量 i 为每次分组的第一个元素下标 
	        for (j = i + gap; j < len; j += gap) { //对步长为gap的元素进行直插排序,当gap为1时,就是直插排序
	            tmp = a[j];  // 备份a[j]的值
	            k = j - gap;  // j初始化为i的前一个元素(与i相差gap长度)
	            while (k >= 0 && a[k] > tmp) {
	                a[k + gap] = a[k]; // 将在a[i]前且比tmp的值大的元素向后移动一位
	                k -= gap;
	            }
	            a[k + gap] = tmp; 
	        }
	    }
    }
}

上一篇:【渝粤教育】 国家开放大学2020年春季 1366英语教学理论与实践 参考试题


下一篇:【渝粤教育】广东开放大学 人工智能 形成性考核 (55)