当前位置: 首页 > news >正文

【数据结构】希尔排序(最小增量排序)

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在学习c++和算法
✈️专栏:数据结构
🐋 希望大家多多支持,咱一起进步!😁
如果文章有啥瑕疵
希望大佬指点一二
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 一、希尔排序的由来
  • 二、算法思路
  • 三、预排序代码实现
  • 四、如何选择gap
  • 五、代码实现(完整版)
  • 六、性能分析

一、希尔排序的由来

  • 从直接插入排序中,我们总结了:(假定要求升序)当原数组是逆序的时候,时间复杂度为O(N2),效率极低。博客地址:点击跳转
  • 当原数组是接近升序或者已经是有序的,那么时间复杂度就是O(N),此时效率最高。

因此,又一位名叫希尔的大佬发现,如果一开始就让数组内的元素接近有序的话,那插入排序的效率不就大大提升了吗?所以,希尔排序是插入排序的优化

二、算法思路

  1. 预排序首先让序列中的元素接近有序

那么如何进行预排序呢?(重点)

其运用了 分组插排 的思想:定义一个变量gap,间隔为gap分为一组进行插入排序

  1. 最后再对数组进行插入排序即可

【画图演示】

在这里插入图片描述

通过以上图片,我们还可以总结一个规律:gap为几,就代表预排序有几组

接下来我们简单实现预排序的代码。

三、预排序代码实现

void ShellSort(int a[], int n)
{// 假设gap为3int gap = 3;// 1. gap是几,就代表有几组for (int i = 0; i < gap; i++){// 2. 间隔为gap为一组进行插入排序for (int j = i; j < n - gap; j += gap){// 下面基本都是插入排序的代码(类似)int end = j;int temp = a[j + gap];while (end >= 0){if (temp < a[end]){a[end + gap] = a[end];end -= gap;}else{a[end + gap] = temp;}}a[end + gap] = temp;}}
}

那么最后就要对整体进行插入排序,这样就能完美实现希尔排序了。但是我们难道还要重新再其后再手搓一个插入排序吗?理论上是可以的,但是没必要。注意看:当间隔gap1时,不就是插入排序了吗?因此,普通插入排序和gap是有关系的。那么应该如何选择gap呢?

四、如何选择gap

gap越大,跳的越快,越不接近有序;gap越小,跳的越慢,越接近有序。

可以为大家验证一下:

  • gap = 3

在这里插入图片描述

是不是越接近有序!

  • gap = 5

在这里插入图片描述

虽然也接近有序,但是没有比gap = 3更接近有序!

那么gap到底取多少合适呢?

解答:gap应该要不断在变化。为什么呢?开头的结论:gap越大,跳的越快,越不接近有序;gap越小,跳的越慢,越接近有序。如果gap是固定大小,给大了越不接近有序,给小了接近有序,但是跳的慢。因此,预排序的为了让更大的数更快的跳到后面,越小数越快跳到前面。这就是为什么gap应该要不断的变化。

  • 最初希尔大佬提出取gap /= 2,为什么呢?因为一个数不断/2,最后的结果一定为1,那么在上面我们说过,当gap = 1,就可以满足整体的插入排序,就不需要再手搓普通插入排序了。

  • 后来Knuth提出取gap = gap / 3 + 1+1为了保证最后gap一定为1,还有人提出取奇数好,也有人提出gap互质好。但无论哪一种主张都没有得到证明。其实都是ok的

五、代码实现(完整版)

void ShellSort(int a[], int n)
{// 3. 如何取gap// gap最大可以取到整个数组的长度nint gap = n;while (gap > 1){// gap = gap / 3 + 1; // 这也是okk的gap /= 2;//  1. gap是几,就代表有几组for (int i = 0; i < gap; i++){// 2. 间隔为gap为一组进行插入排序for (int j = i; j < n - gap; j += gap){int end = j;int temp = a[j + gap];while (end >= 0){if (temp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = temp;}}}
}

【结果展示】

在这里插入图片描述

六、性能分析

  • 时间复杂度

希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算。Knuth大佬进行了大量的试验统计,计算出希尔排序的时间复杂度大约为O(N^1.3)

但是我们可以用代码进行性能测试的对比

在这里插入图片描述

如图,当数据个数是10w时,插入排序和希尔排序时间效率如下所示

在这里插入图片描述

由此看出,希尔排序还是非常的牛逼的~

  • 有人想:希尔排序在预排序的时候不是运用到很多的插入排序,为什么其效率还是比插入排序高?

原因是:其实gap的取值决定数组内的元素是否接近有序,gap越大,排的也越快,但越不接近有序;gap越小,排的也就越慢,但越接近有序。所以一开始gap的值可以设为数组元素个数(gap一定不可能超过数组元素个数),每次进行/2,不断缩小gap,其实最后发现,希尔排序的插入排序的次数其实是小于直接排序的插入次数的。

相关文章:

  • java 旋转方阵
  • 【C++面向对象】13. 接口 / 抽象类*
  • C#几种截取字符串的方法
  • cmmlu数据处理
  • 《持续交付:发布可靠软件的系统方法》 - 目录
  • Windows内的Ubuntu虚拟机安装docker
  • Django路由层之有名分组和无名分组、反向解析、路由分发、伪静态的概念、名称空间、虚拟环境、Django1和Django2的区别
  • 国内领先的五大API接口供应商
  • 【golang】探索for-range遍历实现原理(slice、map、channel)
  • python科研绘图:圆环图
  • 程序员的绝望和欢笑:当拼写错误搞乱了我的代码
  • 前端设计模式之【代理模式】
  • 【Java 进阶篇】JQuery 遍历 —— For 循环的奇妙之旅
  • react hook ts 实现 列表的滚动分页加载,多参数混合混合搜索
  • ctf之流量分析学习
  • CAP理论的例子讲解
  • co.js - 让异步代码同步化
  • ComponentOne 2017 V2版本正式发布
  • flutter的key在widget list的作用以及必要性
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • V4L2视频输入框架概述
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 老板让我十分钟上手nx-admin
  • 说说动画卡顿的解决方案
  • 微信小程序填坑清单
  • 小程序01:wepy框架整合iview webapp UI
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • 一道面试题引发的“血案”
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​学习一下,什么是预包装食品?​
  • #Z0458. 树的中心2
  • #微信小程序:微信小程序常见的配置传旨
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (第27天)Oracle 数据泵转换分区表
  • (分类)KNN算法- 参数调优
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (力扣题库)跳跃游戏II(c++)
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (转)编辑寄语:因为爱心,所以美丽
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .aanva
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • :如何用SQL脚本保存存储过程返回的结果集
  • @Autowired注解的实现原理
  • @FeignClient注解,fallback和fallbackFactory
  • @Repository 注解