• 希尔排序的实现


    引言

            排序在我们生活中十分常见,无论是购物软件中的商品推荐还是名次、排名都与排序算法息息相关。希尔排序是排序中较快的一种,而希尔排序实现的基础是插入排序。

    排序的实现

    插入排序(以升序为例)

            插入排序的原理是从第二个数开始,与前面的数相比较,如果比前面的数大,则与其交换,并且此移动过程会一直持续直到前k(k为此次刚开始移动的数的位置)个数达到有序为止;否则不会移动。代码如下:

    1. void InsertSort(int* a, int n)
    2. {
    3. for (int i = 0; i < n - 1; i++)
    4. {
    5. int end = i;
    6. int tmp = a[end + 1];
    7. while (end >= 0)
    8. {
    9. if (tmp < a[end])
    10. {
    11. a[end + 1] = a[end];
    12. --end;
    13. }
    14. else
    15. {
    16. break;
    17. }
    18. }
    19. a[end + 1] = tmp;
    20. }
    21. }

            我们将一直要改变的那个数设为tmp,将它与前面的数(end)比较,如果tmp较小,则进行交换,先将啊a[end] 覆盖a[end + 1],再--end达到tmp继续与前一个数比较的效果,最后达到效果.

    希尔排序

    希尔排序分为两步:预排序与插入排序.

    预排序

    预排序的目的是先让数组接近有序,将所有数据分为gap组,其代码与插入排序十分类似。

    以该图为例,改预排序的流程是5与9比较,如果比9小,则将9放到原来5的位置,

    再将8与9相比较并与5比较,8比9小,再将9放到8的位置,8比5大,所以再停止

    最后将最后的5进行排序即可.

    再嵌套一层循环使其达到排三组循环的效果

    9--5--8--5

    1--7--6

    2--4--3

    代码如下:

    1. void ShellSort(int* a, int n)
    2. {
    3. int gap = 3;
    4. for (int j = 0; j < gap; j++)
    5. {
    6. for (int i = 0; i < n - gap; i += gap)
    7. {
    8. int end = i;
    9. int tmp = a[end + gap];
    10. while (end >= 0)
    11. {
    12. if (tmp < a[end])
    13. {
    14. a[end + gap] = a[end];
    15. end -= gap;
    16. }
    17. else
    18. {
    19. break;
    20. }
    21. }
    22. a[end + gap] = tmp;
    23. }
    24. }
    25. }

     我们也可以只用两层循环实现,即分组排序的顺序改为

    9--5,1--7,2--4,5--8,7--6,4--3,8--5.,实现代码如下:

    1. //Shell排序的双层循环的写法
    2. void ShellSort(int* a, int n)
    3. {
    4. int gap = 3;
    5. for (int i = 0; i < n - gap; i++)
    6. {
    7. int end = i;
    8. int tmp = a[end + gap];
    9. while (end >= 0)
    10. {
    11. if (tmp < a[end])
    12. {
    13. a[end + gap] = a[end];
    14. end -= gap;
    15. }
    16. else
    17. {
    18. break;
    19. }
    20. }
    21. a[end + gap] = tmp;
    22. }
    23. }
    总排序

    gap一般取整个数组的数量除以三,为保证最后一次一定是1,我们将其设为gap = gap / 3 +1,这样最后就可以由一个插入排序对预排序后的数组进行总排序.并且我们每次预排序都会使数组更加有序,代码如下:

    1. void ShellSort(int* a, int n)
    2. {
    3. int gap = n;
    4. while (gap > 1)
    5. {
    6. gap = gap / 3 + 1;
    7. for (int i = 0; i < n - gap; i++)
    8. {
    9. int end = i;
    10. int tmp = a[end + gap];
    11. while (end >= 0)
    12. {
    13. if (tmp < a[end])
    14. {
    15. a[end + gap] = a[end];
    16. end -= gap;
    17. }
    18. else
    19. {
    20. break;
    21. }
    22. }
    23. a[end + gap] = tmp;
    24. }
    25. }
    26. }

    希尔排序的速度

    在release环境下,测试100,000个数据,其结果如下:

    我们发现,希尔排序的速度是与堆排序是一个数量级的,而插入排序的速度也是比冒泡排序要快一个量级的.

    测试1,000,000个数据

    测试10,000,000个数据

    堆排序的时间复杂度是O(n\log n),所以希尔排序的速度算是非常快的,有实践意义。

    希尔排序的时间复杂度是 O(n^{1.3}).

  • 相关阅读:
    C#学习记录——线程的简介及基本操作
    Flutter自定义对话框返回相关问题汇总
    D. Make Them Equal(dp + 范围优化 )
    AcWing 4520:质数 ← BFS
    12.Blender 界面介绍(上)及物体基础编辑操作
    Spring boot admin 服务监控利器
    【Nginx28】Nginx学习:代理模块(二)缓存与错误处理
    一部分热点识别的技术方案记录
    读书笔记:python+vue实战派
    D : DS 顺序表之循环移位
  • 原文地址:https://blog.csdn.net/Frenemy__/article/details/139995960