当前位置: 首页 > 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;改变了数十亿用户的社交方式。展望…...

WhatsNew vs 其他更新提示库:为什么它是iOS开发者的首选

WhatsNew vs 其他更新提示库&#xff1a;为什么它是iOS开发者的首选 【免费下载链接】WhatsNew Showcase new features after an app update similar to Pages, Numbers and Keynote. 项目地址: https://gitcode.com/gh_mirrors/wh/WhatsNew 在iOS应用开发中&#xff0c…...

3步掌握Windows字体优化:Better ClearType Tuner完整使用指南

3步掌握Windows字体优化&#xff1a;Better ClearType Tuner完整使用指南 【免费下载链接】BetterClearTypeTuner A better way to configure ClearType font smoothing on Windows 10. 项目地址: https://gitcode.com/gh_mirrors/be/BetterClearTypeTuner 你是否曾经在…...

Navicat Mac版试用期重置终极指南:3种简单方法实现永久免费使用

Navicat Mac版试用期重置终极指南&#xff1a;3种简单方法实现永久免费使用 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 你…...

周末造AI公司:无代码+AI工作流48小时MVP实战

1. 项目概述&#xff1a;当“周末造AI公司”成为可复现的工程实践你有没有见过这样的场景&#xff1a;周五下班前&#xff0c;三个人在咖啡馆里画了一张白板草图&#xff1b;周六上午用Notion搭好产品框架、下午用Glide连上Airtable跑通用户注册流程&#xff1b;周日下午把Chat…...

皮线、裸纤总是分不清?试试这个算法一键校准技巧

不知道你有没有经历过这种工地上的"崩溃瞬间"&#xff1a;大热天蹲在居民楼昏暗的楼道里&#xff0c;蚊子在耳边嗡嗡叫&#xff0c;你手里正拉着一根刚从住户门缝里拽出来的皮线光缆&#xff0c;准备跟分纤箱引出来的单模裸纤做熔接。结果放进机器&#xff0c;合上盖…...

AI Agent智能体技术:从问答到执行的范式革命

标签:AI Agent、大模型、智能体、LangChain、ReAct、Function Calling 📖 前言 2026年5月20日,谷歌I/O 2026大会在美国加州山景城开幕。谷歌CEO桑达尔皮查伊(Sundar Pichai)在大会上宣布:“我们已正式进入’智能体Gemini时代’。”就在同一天,百度Create 2026大会上,…...

APT32F110 RTC模块深度测评:从硬件原理到低功耗应用实战

1. 项目概述与核心价值最近在捣鼓爱普特APT32F110这块开发板&#xff0c;发现它的RTC&#xff08;实时时钟&#xff09;功能挺有意思。对于很多嵌入式项目来说&#xff0c;比如智能家居的定时开关、数据采集设备的定时唤醒、或者简单的电子钟&#xff0c;一个靠谱的RTC模块是必…...

2026年国内镜像站选择指南:一站接入GPT-5.5和主流AI模型

先交代一下背景。2026年的大模型格局已经变了——GPT-5.5、Claude、Gemini、Grok 各有各的强项&#xff0c;做项目的时候经常需要这个模型写代码、那个模型分析文档、再来一个做联网搜索。但问题是&#xff0c;国内想用上这些模型&#xff0c;光解决"能访问"就已经够…...

HC-05蓝牙模块连接Arduino/STM32的实战避坑指南:从3.3V/5V电平匹配到手机APP调试全流程

HC-05蓝牙模块连接Arduino/STM32的实战避坑指南&#xff1a;从3.3V/5V电平匹配到手机APP调试全流程 当你第一次尝试将HC-05蓝牙模块连接到Arduino或STM32开发板时&#xff0c;可能会遇到各种令人沮丧的问题&#xff1a;模块不响应、手机搜索不到设备、数据传输不稳定。这些问题…...

别再为Tesseract中文识别报错发愁了!手把手教你搞定chi_sim语言包和环境变量配置

Tesseract中文识别实战&#xff1a;从报错排查到精准配置的全流程指南 当你在终端兴奋地输入第一行Tesseract命令&#xff0c;却看到刺眼的Failed loading language chi_sim报错时&#xff0c;那种挫败感我深有体会。这个看似简单的错误背后&#xff0c;往往隐藏着路径配置、文…...