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

【数据结构与算法】希尔排序:基于插入排序的高效排序算法

            💓 博客主页:倔强的石头的CSDN主页 

           📝Gitee主页:倔强的石头的gitee主页

            ⏩ 文章专栏:《数据结构与算法》

                                  期待您的关注

1b7335aca73b41609b7f05d1d366f476.gif

目录

一、引言 

二、基本原理

三、实现步骤

四、C语言实现

五、性能分析

1. 时间复杂度:近似为O(Nlog2N)

2. 空间复杂度:O(1)

3. 稳定性:不稳定的

六、优化

七、应用场景


一、引言 

希尔排序(Shell Sort)是插入排序的一种更高效的改进版本,也称为缩小增量排序。

希尔排序由Donald Shell于1959年提出,并在其发表的论文“A high-speed sorting procedure”中详细描述了该算法。希尔排序的直接灵感来源于插入排序,但它在插入排序的基础上进行了显著的改进,旨在提高排序效率,特别是针对大规模数据集

想要读懂希尔排序,最好先理解插入排序,参考下面这篇文章

【数据结构与算法】深入解析插入排序算法:原理、实现与优化-CSDN博客

二、基本原理

希尔排序的基本思想是先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次标准的直接插入排序。

这里的“基本有序”是指待排序的数组元素值满足某个增量序列的“局部有序”,即对于某个变量gap,序列中所有距离为gap的元素之间是有序的。随着变量gap的逐渐减小,当gap减小到1时,整个序列恰好被“基本有序”,此时再对全体元素进行一次直接插入排序即可

三、实现步骤

 
1.外循环进行多轮预排序
选择一个变量序列:

这个序列是逐渐减小的,gap的值较大时,数据可以更快的前后变动,但不容易"基本有序";gap较小时数据前后变动较慢,但更接近"基本有序"。  通常可以选取gap = n/3, gap = gap/3, ...,直到gap= 1。

但是要注意,如果直接每次都/3,可能面临的情况就是最后一组gap的值跳过了1,比如n=8时,gap第一次等于2,第二次等于0,解决方法也很简单,gap每次不是/3,而是gap=gap/3+1,就可以让gap最后一次一定会减小到1

2.第二层循环,每一轮预排序中进行分组
按gap进行分组:根据当前的变量gap,将待排序的数组元素下标按gap分组,总共可以分成gap组。比如gap为3时,每一组元素的首元素分别是0,1,2

3.第三层循环,分组之后,控制组里数据执行插入排序
每一组的数据有n/gap个,下标为0,gap, 2gap, 3gap,...的元素分为一组;下标为1,gap+1,2gap+1,3gap+1……的元素分为一组……


这一层循环一个需要注意的细节就是预防数组的越界:每一组分组数据的最后一个数据一般不会是数组的最后一个数据。每次选取的要插入的数据下标是end+gap,那么这个下标不能超过n-gap。比如数组有10个元素,gap为3,第一组数据最后一个数据的下标是9,要保证这一组数据访问到下标9之后,不再向后访问,因为下一次访问end为9,要插入的数据,9+gap的位置已经没有数据了。


4.第四层循环,实现插入排序的过程
每个数据向前扫描和移动,找到合适的位置后插入,直接在插入排序代码的基础上稍加修改即可

5.递减变量gap并重复上述分组排序过程:

每完成一轮按变量gap的分组排序后,将变量gap减小,然后重复分组排序过程,直到变量gap为1,此时整个数组恰好被分成一组,进行最后一次直接插入排序。
 

四、C语言实现

void ShellSort1(int* a, int n)//希尔排序升序
{int gap = n;while (gap > 1)//多组预排序,最后一组gap==1为直接插入排序{gap = gap / 3 + 1;for (int i = 0; i <gap; i++)//控制分组的组数:gap组{for (int j = i; j < n - gap; j += gap)//控制每组的插入元素个数:n/gap个{int key = a[j+gap];int end = j;while (end >= 0 && a[end] > key)//比较和移动元素{a[end + gap] = a[end];end -= gap;}a[end + gap] = key;//满足大小关系后插入到指定位置}}}
}void ShellSort2(int* a, int n)//希尔排序降序
{int gap = n;while (gap > 1)//多组预排序,最后一组gap==1为直接插入排序{gap = gap / 3 + 1;for (int i = 0; i < gap; i++)//控制分组的组数:gap组{for (int j = i; j < n - gap; j += gap)//控制每组的插入元素个数:n/gap个{int key = a[j + gap];int end = j;while (end >= 0 && a[end] < key)//比较和移动元素{a[end + gap] = a[end];end -= gap;}a[end + gap] = key;//满足大小关系后插入到指定位置}}}
}

五、性能分析

1. 时间复杂度:近似为O(Nlog2N)

希尔排序的时间复杂度并不是一个定值,它依赖于增量序列(gap序列)的选取

  • 平均时间复杂度:在多数情况下,希尔排序的平均时间复杂度可以近似为O(Nlog2N),但这并不是一个严格的结论,因为实际性能会受到增量序列的具体选择和数据初始状态的影响。
  • 最佳时间复杂度:在最佳情况下,即数据已经接近有序时,希尔排序可以接近线性排序的效率,但具体数值难以准确给出。
  • 最差时间复杂度:在最坏情况下,希尔排序的时间复杂度仍然是O(N^2)。这通常发生在增量序列选择不当,导致算法无法有效减少数据比较和移动次数时。

2. 空间复杂度:O(1)

希尔排序是原地排序算法,它只需要一个额外的空间来存储临时变量(用于数据交换),因此其空间复杂度为O(1)。这意味着希尔排序在排序过程中不会占用额外的存储空间,这对于内存资源有限的环境非常有利。

3. 稳定性:不稳定的

希尔排序是不稳定的排序算法。在排序过程中,由于存在跳跃式的比较和移动,相同元素的相对位置可能会发生变化。因此,在需要保持元素原始顺序的场景中,希尔排序可能不是最佳选择。

六、优化

将第二层第三层循环合为一层循环,
以前是四层循环时,我们是将分组作为一层循环,每组里的数据插入作为一层循环
将两层循环合为一层之后,不是一组一组进行预排序,而是将数据逐个的,与它对应的组里的数据进行预排序,互不影响
优化之后代码更加简洁,但效率没有提升

void ShellSort(int* a, int n)//希尔排序升序代码优化版(效率没有提升)
{int gap = n;while (gap > 1)//多组预排序,最后一组gap==1为直接插入排序{gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++)//控制多组以及插入元素个数{int key = a[i + gap];int end = i;while (end >= 0 && a[end] > key)//比较和移动元素{a[end + gap] = a[end];end -= gap;}a[end + gap] = key;//满足大小关系后插入到指定位置}}
}

七、应用场景

希尔排序(Shell Sort)由于其实现简单且在某些情况下表现良好,因此在一些特定的应用场景中得到了应用。以下是一些希尔排序可能适用的场景:

  1. 中等规模数据集:对于小到中等规模的数据集(比如几千个元素),希尔排序通常能够提供良好的性能。在这些情况下,希尔排序可能比更复杂的排序算法(如快速排序、归并排序等)更容易实现且效率相当。

  2. 部分有序数据集:如果数据集已经部分有序(即元素接近它们的最终位置),希尔排序可以利用这一点来更快地完成排序。因为希尔排序通过引入间隔(gap)来允许元素在更远的距离上进行交换,这有助于减少数据移动的次数,从而加速排序过程。

  3. 内存受限的环境:希尔排序是原地排序算法,只需要O(1)的额外空间。在内存受限的环境中(如嵌入式系统或大型数据集排序时内存使用受到严格控制的场景),这一点尤为重要。

  4. 实时系统:在一些实时系统中,排序操作的响应时间非常关键。希尔排序由于其实现简单且通常能够快速完成排序,因此可能是一个不错的选择。尽管在最坏情况下其时间复杂度为O(N^2),但在实际应用中,它往往能够更快地完成排序,特别是在数据集部分有序或规模适中的情况下。

  5. 教育目的:在教学和学习排序算法的过程中,希尔排序是一个很好的例子,因为它展示了如何通过引入简单的改进(即间隔序列)来显著提高基本排序算法(如插入排序)的性能。

然而,需要注意的是,对于非常大的数据集或对数据排序的稳定性有严格要求的应用场景,希尔排序可能不是最佳选择。在这些情况下,可能需要考虑使用更高效的排序算法(如快速排序、归并排序或堆排序)或稳定的排序算法(如归并排序、冒泡排序等)。

总之,希尔排序适用于中等规模、部分有序、内存受限或需要快速响应的实时系统等场景。但在选择排序算法时,还需要根据具体的应用需求和数据集特点进行综合考虑。

相关文章:

【数据结构与算法】希尔排序:基于插入排序的高效排序算法

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 二、基本原理 三、实现步骤 四、C语言实现 五、性能分析 1. 时间复杂度…...

关于正点原子的alpha开发板的启动函数(汇编,自己的认识)

我傻逼了&#xff0c;这里的注释还是不要用&#xff1b; 全部换成 /* */ 这里就分为两块&#xff0c;一部分是复位中断部分&#xff0c;第二部分就是IRQ部分&#xff08;中断部分最重要&#xff09; 我就围绕着两部分来展开我的认识 首先声明全局 .global_start 在 ARM 架…...

Deep Layer Aggregation【方法部分解读】

摘要: 视觉识别需要跨越从低到高的层次、从小到大的尺度以及从精细到粗略的分辨率的丰富表示。即使卷积网络的特征层次很深,单独的一层信息也不足够:复合和聚合这些表示可以改进对“是什么”和“在哪里”的推断。架构上的努力正在探索网络骨干的许多维度,设计更深或更宽的架…...

大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】

大数据面试SQL题复习思路一网打尽&#xff01;(文档见评论区)_哔哩哔哩_bilibiliHive SQL 大厂必考常用窗口函数及相关面试题 大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】大数据面试SQL题-笔记02【...】 目录 01、力扣网-sql题 1、高频SQL50题&#xff08…...

零基础自学爬虫技术该从哪里开始入手?

零基础自学爬虫技术可以从以下几个方面入手&#xff1a; 一、学习基础编程语言 Python 是爬虫开发的首选语言&#xff0c;因此首先需要学习 Python 编程语言的基础知识。这包括&#xff1a; 语法基础&#xff1a;学习 Python 的基本语法&#xff0c;如变量定义、数据类型、控…...

CV11_模型部署pytorch转ONNX

如果自己的模型中的一些算子&#xff0c;ONNX内部没有&#xff0c;那么需要自己去实现。 1.1 配置环境 安装ONNX pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple 安装推理引擎ONNX Runtime pip install onnxruntime -i https://pypi.tuna.tsinghua.edu.cn/si…...

Redis的使用(四)常见使用场景-缓存使用技巧

1.绪论 redis本质上就是一个缓存框架&#xff0c;所以我们需要研究如何使用redis来缓存数据&#xff0c;并且如何解决缓存中的常见问题&#xff0c;缓存穿透&#xff0c;缓存击穿&#xff0c;缓存雪崩&#xff0c;以及如何来解决缓存一致性问题。 2.缓存的优缺点 2.1 缓存的…...

BERT架构的深入解析

BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是由Google在2018年提出的一种基于Transformer架构的预训练模型&#xff0c;迅速成为自然语言处理&#xff08;NLP&#xff09;领域的一个里程碑。BERT通过双向编码器表示和预训练策略&am…...

数字孪生技术如何助力低空经济飞跃式发展?

一、什么是低空经济&#xff1f; 低空经济&#xff0c;是一个以通用航空产业为主导的经济形态&#xff0c;它涵盖了低空飞行、航空旅游、航空物流、应急救援等多个领域。它以垂直起降型飞机和无人驾驶航空器为载体&#xff0c;通过载人、载货及其他作业等多场景低空飞行活动&a…...

HTTP背后的故事:理解现代网络如何工作的关键(二)

一.认识请求方法(method) 1.GET方法 请求体中的首行包括&#xff1a;方法&#xff0c;URL&#xff0c;版本号 方法描述的是这次请求&#xff0c;是具体去做什么 GET方法&#xff1a; 1.GET 是最常用的 HTTP 方法. 常用于获取服务器上的某个资源。 2.在浏览器中直接输入 UR…...

数据流通环节如何规避安全风险

由于参与数据流通与交易的数据要素资源通常是经过组织加工的高质量数据集&#xff0c;甚至可能涉及国家核心战略利益&#xff0c;一旦发生针对数据流通环节的恶意事件&#xff0c;将造成较大负面影响&#xff0c;对数据要素市场的价值激活造成潜在威胁。具体来说&#xff0c;数…...

部署k8s 1.28.9版本

继上篇通过vagrant与virtualBox实现虚拟机的安装。笔者已经将原有的vmware版本的虚拟机卸载掉了。这个场景下&#xff0c;需要重新安装k8s 相关组件。由于之前写的一篇文章本身也没有截图。只有命令。所以趁着现在。写一篇&#xff0c;完整版带截图的步骤。现在行业这么卷。离…...

实验二:图像灰度修正

目录 一、实验目的 二、实验原理 三、实验内容 四、源程序和结果 源程序(python): 结果: 五、结果分析 一、实验目的 掌握常用的图像灰度级修正方法,包括图象的线性和非线性灰度点运算和直方图均衡化法,加深对灰度直方图的理解。掌握对比度增强、直方图增强的原理,…...

bash: ip: command not found

输入&#xff1a; ip addr 报错&#xff1a; bash: ip: command not found 报错解释&#xff1a; 这个错误表明在Docker容器中尝试执行ip addr命令时&#xff0c;找不到ip命令。这通常意味着iproute2包没有在容器的Linux发行版中安装或者没有正确地设置在容器的环境变量PA…...

全开源TikTok跨境商城源码/TikTok内嵌商城/前端uniapp+后端+搭建教程

多语言跨境电商外贸商城 TikTok内嵌商城&#xff0c;商家入驻一键铺货一键提货 全开源完美运营 海外版抖音TikTok商城系统源码&#xff0c;TikToK内嵌商城&#xff0c;跨境商城系统源码 接在tiktok里面的商城。tiktok内嵌&#xff0c;也可单独分开出来当独立站运营 二十一种…...

云原生、Serverless、微服务概念

云原生&#xff08;Cloud Native&#xff09; 云原生是一种设计和构建应用程序的方法&#xff0c;旨在充分利用云计算的优势。云原生应用程序通常具有以下特征&#xff1a; 容器化&#xff1a;应用程序和其依赖项被打包在容器中&#xff0c;确保一致的运行环境。常用的容器技…...

Windows上LabVIEW编译生成可执行程序

LabVIEW项目浏览器(Project Explorer)中的"Build Specifications"就是用来配置项目发布方法的。在"Build Specifications"右键菜单中选取"New"&#xff0c;可以看到程序有几种不同的发布方法&#xff1a;Application(EXE)、Installer、.Net Inte…...

ref 和 reactive 区别

在Vue 3中&#xff0c;ref和reactive都是用于创建响应式数据的API&#xff0c;但它们之间存在一些关键的区别。以下是ref和reactive的主要区别&#xff1a; 1. 数据类型处理 ref&#xff1a;主要用于定义基本类型的数据&#xff08;如字符串、数字、布尔值等&#xff09;以及…...

深度学习计算机视觉中, 多尺度特征和上下文特征的区别是?

在深度学习和计算机视觉中&#xff0c;多尺度特征和上下文特征都是用来捕捉和理解图像中复杂模式和关系的重要概念&#xff0c;但它们的侧重点有所不同。 多尺度特征 (Multi-scale Features) 多尺度特征是指在不同尺度上对图像进行特征提取&#xff0c;以捕捉不同尺度的物体特…...

Facebook未来展望:数字社交平台的进化之路

在信息技术日新月异的时代&#xff0c;社交媒体平台不仅是人们交流沟通的重要工具&#xff0c;更是推动社会进步和变革的重要力量。作为全球最大的社交媒体平台之一&#xff0c;Facebook在过去十多年里&#xff0c;不断创新和发展&#xff0c;改变了数十亿用户的社交方式。展望…...

基于OFA的智能零售解决方案:商品图像自动问答系统

基于OFA的智能零售解决方案&#xff1a;商品图像自动问答系统 1. 引言 走进任何一家现代零售店&#xff0c;你都会看到顾客拿着商品反复查看标签、比较价格、寻找成分信息。这种场景每天都在全球数百万家商店中重复上演。店员们疲于应对各种"这个产品有没有过敏源&#…...

告别鼠标流!用STM32CubeIDE快捷键玩转代码导航与重构(实战演示)

告别鼠标流&#xff01;用STM32CubeIDE快捷键玩转代码导航与重构&#xff08;实战演示&#xff09; 在嵌入式开发的世界里&#xff0c;效率就是生命线。当你面对一个庞大的STM32工程&#xff0c;频繁在数千行代码中穿梭时&#xff0c;每一次不必要的鼠标点击都在蚕食宝贵的开发…...

华为2288X V5服务器RAID配置实战:为iMaster NCE-CampusInsight单机部署打好地基

华为2288X V5服务器RAID配置全攻略&#xff1a;从硬件准备到iMaster NCE-CampusInsight部署 当企业级网络分析平台iMaster NCE-CampusInsight遇上华为2288X V5服务器&#xff0c;硬件配置的合理性直接决定了后续系统运行的稳定性与数据安全性。作为部署流程中的首个技术攻坚点&…...

history 常见优化配置

文章目录 一、写在哪个文件生效?(关键) ✅ Bash 环境下生效位置(最常见) 1️⃣ 全局生效(所有用户) ✅ 推荐方式(最规范) 2️⃣ 全局兜底(老系统) 3️⃣ 当前用户生效 ✅ 各文件加载顺序(很重要) 二、不同场景推荐配置位置 三、验证是否生效 四、一句话总结(运维…...

proxy-GS:vulkan编译(记录)

文章目录第一阶段&#xff1a;干净的基准环境配置第二阶段&#xff1a;核心 CUDA 算子安装第三阶段&#xff1a;代码“外科手术”&#xff08;解决 API 不匹配&#xff09;第四阶段&#xff1a;Vulkan 后端终极编译第五阶段&#xff1a;漫游验证Proxy-GS 的配置vulkan流程。看到…...

18.children 这个 props 的意义何在?该怎样正确使用?

在 React 里&#xff0c;children 是一个非常特殊、非常常用的 prop&#xff0c; 它专门用来接收&#xff1a;写在组件标签中间的那一部分内容。你可以把它理解为&#xff1a;组件外层负责搭“外壳”&#xff0c;children 负责装进这个壳里的“内容物”。一、children 到底是什…...

前端可访问性:让所有人都能使用你的应用

前端可访问性&#xff1a;让所有人都能使用你的应用 一、引言 又到了我这个毒舌工匠上线的时间了&#xff01;今天咱们来聊聊前端可访问性这个话题。别以为可访问性只是给残障人士用的&#xff0c;实际上&#xff0c;良好的可访问性能够让所有人都能更好地使用你的应用&#xf…...

AI Agent在智能制造中的应用:多智能体协同生产调度案例

AI Agent在智能制造中的应用&#xff1a;多智能体协同生产调度案例 摘要/引言 各位读者好&#xff0c;我是深耕工业软件与分布式AI系统近十年的技术博主&#xff0c;也是前西门子离散制造数字化转型中心的架构师。今天这篇文章&#xff0c;我们要聊的绝对是当前智能制造领域最…...

论文AI率80%+的紧急处理方案,答辩前用得上

距离答辩3天&#xff0c;AI率检出80%——这是最糟糕的时间点碰到最糟糕的问题。 不要慌&#xff0c;这个情况有成熟的处理方案&#xff0c;我见过很多人在这个时间节点成功降下来的。下面是紧急情况下的处理方法&#xff0c;按照时间紧迫程度分了几个场景。 先做一个判断&…...

多模态整合进阶必读:MIT APOLLO框架核心思想(非常详细),从原理到精通,收藏这一篇就够了!

麻省理工学院与瑞士苏黎世联邦理工学院的联合研究团队&#xff0c;提出了计算框架 APOLLO&#xff0c;即通过潜变量优化学习部分重叠潜空间的自编码器&#xff0c;其通过显式建模共享信息和模态特异性信息&#xff0c;为更全面、精准地解析细胞状态及其调控逻辑提供了一条可行的…...