手撕排序算法系列之:希尔排序。

从本篇文章开始,我会介绍并分析常见的几种排序,大致包括插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等。

大家可以点击此链接阅读其他排序算法:排序算法_大合集(data-structure_Sort)

本篇主要来手撕希尔排序~~

目录

1.常见的排序算法

1.1 插入排序基本思想

2.希尔排序

2.1希尔排序(缩小增量排序)

2.1.1预排序阶段

2.1.2插入排序阶段

2.2单趟希尔排序

2.2.1思路分析

3.希尔排序实现代码

4.希尔排序测试

5.希尔排序的时间复杂度

6.希尔排序和直接插入排序效率测试

6.1测试

6.2结论

6.2.1随机生成数

6.2.2有序数组

7.希尔排序特性总结

1.常见的排序算法

1.1 插入排序基本思想

直接插入排序是一种简单的插入排序法,其基本思想是:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列

实际中我们玩扑克牌时,就用了插入排序的思想

2.希尔排序

2.1希尔排序(缩小增量排序)

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数gap,把待排序文件中所有记录分成多个组,所有距离相差gap的记录分在同一组内,并对每一组内的记录进行排序。然后,取gap = gap/3+1重复上述分组和排序的工作。当gap到达=1时,所有记录在同一组内排好序

画图分析:

如上图所示,如果我们要默认升序排序:

2.1.1预排序阶段

1、在第一趟的时候,我们取gap = 5,此时9和4,1和8,2和6,5和3,7和5分到了一组,然后我们在每组之内进行比较,如果前面的数字大于后面的数字,就交换,此时每组中较小的数字就被交换到前面,较大的数字没交换到了后面。

2、在第二趟的时候,我们取gap = gap/3+1(除以三是一个普遍的写法,这里的重点是为什么要+1,这是因为如果gap小于3的情况下,gap/3会让gap=0,此时就会陷入死循环),这时gap= 2,4和2,5,8,5分到了一组,1,3,9,6,7分到了一组。此时,在一组内,进行排序,这一组就有序。

2.1.2插入排序阶段

3、待gap = 1得时候,我们就是用插入排序,这时候经过之前的预排阶段,整个数组已经变得大致有序了,较大的数字都会被移到后面,较小的数字都会移到前面,此时是用插入排序,效率就会很高。

2.2单趟希尔排序

2.2.1思路分析

单趟希尔排序就是将差为gap的数字分为一组,较大的放在后面,较小的放在前面

    for (int i = 0; i < n - gap; ++i)//++i  可以直接让多组同时进行交换(只是少写个循环但是不提高任何效率){int end = i;int tmp = a[end + gap];while (end >= 0){if(tmp < a[end]){ a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}

具体插入排序的思想大家可以参考博文:[ 数据结构 -- 手撕排序算法第一篇 ] 插入排序

3.希尔排序实现代码

在单趟排序的基础上,加上一个gap循环即可

void ShellSort(int* a, int n)
{//1.gap > 1  预排序//2.gap == 1 直接插入排序int gap = n;while (gap > 1){gap = gap / 3 + 1;//后面 +1 保证当gap小于3时能让gap == 1for (int i = 0; i < n - gap; ++i)//++i  可以直接让多组同时进行交换(只是少写个循环但是不提高任何效率){int end = i;int tmp = a[end + gap];while (end >= 0){if(tmp < a[end]){ a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

4.希尔排序测试

void ShellSort(int* a, int n)
{//1.gap > 1  预排序//2.gap == 1 直接插入排序int gap = n;while (gap > 1){gap = gap / 3 + 1;//后面 +1 保证当gap小于3时能让gap == 1for (int i = 0; i < n - gap; ++i)//++i  可以直接让多组同时进行交换(只是少写个循环但是不提高任何效率){int end = i;int tmp = a[end + gap];while (end >= 0){if(tmp < a[end]){ a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}//希尔排序
void TestShellSort()
{int a[] = { 9, 1, 2, 5, 7, 4, 8, 6, 3, 5 };ShellSort(a, sizeof(a) / sizeof(int));PrintArray(a, sizeof(a) / sizeof(int));
}int main()
{//希尔排序TestShellSort();return 0;
}

测试结果:

5.希尔排序的时间复杂度

希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定。

但是我们可以将希尔排序的时间复杂度相比较直接插入排序进行分析,在最坏情况下也就是逆序排顺序,假设有N个数字。直接插入排序的时间复杂度是O(n^2),但是如果使用希尔排序此时进行分组时候每个组组进行排序,在最后gap=1时时间复杂度可以认为是O(n),所以结合起来希尔排序的时间复杂度是大于O(n)小于O(n^2)。

但是希尔排序在一种情况下也是存在缺点的,这种情况下就是原数组本身有序,那直接插入排序的时间复杂度是O(N),而使用希尔排序在gap>1的时候进行预排序其实是没有作用的,但是计算机是不知道的,还是会做一遍预排序,当gap = 1的时候在直接插入排序。因此时间复杂度是大于O(N)。但是这毕竟是少数情况,大多数排序都是随机数组或是逆序排顺序。

以下是两本书中对希尔排序时间复杂度的描述:

因为我们的gap是按照Knuth提出的方式取值的,而且Knuth进行了大量的试验统计,我们暂时就按照:
来算。

为了更好的比较希尔排序和直接插入排序的效率,我们可以生成一组随机数进行比较查看他们所消耗的时间。

6.希尔排序和直接插入排序效率测试

6.1测试

我们创建一个数组,数组的元素个数有100000个,让其数字全部随机生成,我们通过希尔排序和直接插入排序分别对这个数组进行排序。观察他们所消耗的时间。

//时间对比
void TestOP()
{srand(time(0));const int N = 100000;int* a1 = (int*)malloc(sizeof(int) * N);int* a2 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; ++i){a1[i] = rand();a2[i] = a1[i];}int begin1 = clock();InsertSort(a1, N);int end1 = clock();int begin2 = clock();ShellSort(a2, N);int end2 = clock();printf("InsertSort:%d\n", end1 - begin1);printf("ShellSort:%d\n", end2 - begin2);free(a1);free(a2);
}int main()
{TestOP();return 0;
}

6.2结论

6.2.1随机生成数

通过结果我们能够发现,在100000个数字下,希尔排序的效率远远高于直接插入排序。

我们也可以改变数组大小再测试测试

我们能够发现当数组越大时,希尔排序比直接插入排序的效率越高。

6.2.2有序数组

当我们让数组变得有序我们再查看结果:

正如我们所分析的那样,当数组本身有序时,希尔排序的预排序阶段就会不起作用,此时希尔排序的效率不及直接插入排序。

7.希尔排序特性总结

希尔排序的特性总结:
1. 希尔排序是对直接插入排序的优化。
2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定。
4. 稳定性:不稳定

(本篇完)

[ 数据结构 -- 手撕排序算法第三篇 ] 希尔排序相关推荐

  1. 数据结构—排序算法总结(插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、合并排序、计数排序)

    *排序 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 稳定性 在待排序的数组中,如果出现多个相同的关键字,例如:98751555512,中出现重复的数字,在 ...

  2. 【python算法系列三】 希尔排序算法

    希尔排序,又叫"缩小增量排序",是对插入排序进行优化后产生的一种排序算法.它的执行思路是:把数组内的元素按下标增量分组,对每一组元素进行插入排序后,缩小增量并重复之前的步骤,直到增 ...

  3. 排序上---(排序概念,常见排序算法,直接插入,希尔排序,直接选择排序,堆排序)

    排序的概念 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对 ...

  4. [ 数据结构 -- 手撕排序算法第四篇 ] 选择排序

    手撕排序算法系列之第四篇:选择排序. 从本篇文章开始,我会介绍并分析常见的几种排序,大致包括直接插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等. 大家可以点击此链接阅读其他排序算 ...

  5. 排序算法(三)—— 插入法排序算法

    1.插入法排序算法介绍 插入法是一个比较常用的排序方法.插入法排序的思路就是将要排序的数组分两个区间,一个是已排序区间,一个是未排序区间.初始时,默认第一个元素是已排序区间的,后面的所有元素为未排序区 ...

  6. 【Java】5大排序算法总结(插入排序+希尔排序+选择排序+堆排序+冒泡排序)

    快速导航: 1. 稳定性 2 . 插入排序 3. 希尔排序 4. 选择排序 5. 堆排序 6 冒泡排序 1. 稳定性 两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法 ...

  7. shell排序_Python排序算法(五)希尔排序

    一. 核心思想 希尔排序(shell_Sort),也称递减增量排序算法,是插入排序的一种更高效的改进版本.基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录& ...

  8. Python排序算法(二) 快速排序、希尔排序、归并排序

    这篇文章有的排序算法是:快速排序.希尔排序.归并排序. 快速排序 ''' 快速排序 '''def quick_sort(aList, first, last):if first >= last: ...

  9. 希尔排序的详细过程_算法系列: 10大常见排序算法(4)希尔排序

    本课程是从少年编程网转载的课程,目标是向中学生详细介绍计算机比赛涉及的编程语言,数据结构和算法.编程学习最好使用计算机,请登陆 www.3dian14.org (免费注册,免费学习). 一句 希尔排序 ...

最新文章

  1. 今天安装VisualSVN 不小心删掉了安装目录,再次安装 修改 移除提示UninstallWMISchemaExecute (0x8004401e) when updating VisualSV
  2. SAP WM Interview Questions
  3. 从头开始写框架(一):浅谈JS模块化发展
  4. mysql 数据类型详解_MySQL笔记之数据类型详解
  5. 前端服务器获取js文件偶尔慢_我所认识的前端性能优化
  6. ui原型设计工具_UI设计师的工具包,用于专业模型,原型和产品插图
  7. python中的基本数据结构
  8. 【电脑问题】win10更新后,java环境有问题:Error:missing `server` JVM at `*:\java\jre8\bin\server\jvm.dll`
  9. (28)FPGA面试技能提升篇(SATA接口)
  10. 大航海北斗星导航系统V1.10
  11. 一些有意思的博客收藏
  12. 谷歌云盘文件快速下载方法
  13. 【教程】InstallShield使用完全教程
  14. 计算机网络机房巡视表,机房巡查记录表.doc
  15. 如何删除tmp计算机桌面,temp文件删不掉怎么办
  16. 软件测试工程师岗位职责、岗位要求
  17. 纽约科技行业十大高薪职位
  18. 双模 5G 拍照最强?— X30 Pro 评测
  19. CentOS7 安装 chrome
  20. 模糊 C 均值聚类(Fuzzy C-Means)

热门文章

  1. 悼念我那行尸走肉的23年!
  2. 未来的计算机元器件,代表未来的不是量子计算机,光计算机才是?
  3. 用c语言写生成 mif文件的软件,生成mif文件的几种方法总结
  4. 【TS】在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型
  5. I Squared Capital将与Rubis就欧洲领先的石油产品、化学品、农产品和化肥存储公司Rubis Terminal开展合作
  6. Axure RP 8的矩形
  7. unity3d 模拟人体皮肤
  8. cmd重启网络服务命令
  9. 【WP8】自定义配置存储类
  10. linux开机dracut界面_安装 CentOS 7 的时候出现 Dracut: 信息后无法进行下去的解决办法...