希尔排序算法

目录

ShellSort希尔排序

整体思路

图解分析

【1】预排序

单组排序

多组并排

【2】直接插入排序

关于gap取值 

总代码实现

时间复杂度


ShellSort希尔排序

希尔排序法又称缩小增量法。

  • 希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个 组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工 作。当到达=1时,所有记录在统一组内排好序。 
  • 希尔排序=预排序+直接插入排序
  • 预排序:让大的数值更快的到达后面,小的数值更快的到达前面。(达到一个让数组元素接近顺序的效果)
  • gap是间距值❗
  • 直接插入排序相当于gap==1,希尔排序相当gap存在值了。

希尔排序的特性总结:

1. 希尔排序是对直接插入排序的优化。

2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就 会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

3. 稳定性:不稳定 

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

《数据结构(C语言版)》--- 严蔚敏

《数据结构-用面相对象方法与C++描述》--- 殷人昆

整体思路

  • gap是数值之间的间距值❗
  • 直接插入排序相当于gap==1,希尔排序相当gap存在值了。
  • gap是几,就可以把整体分为几组。(除去gap = n的情况)(gap=gap/2或者gap=gap/3+1)
  • 分组和每组里面的元素个数的关系
  1. gap = n(gap随着n的变换而变化,gap的值不固定)
  2. gap/2(每次gap组,每组里面的元素个数:2,4,8......)*2 【n/2,n/4,n/8....】
  3. gap/3+1 (每次gap组,每组里面的元素个数:3,9,27...)*2【n/3,n/9,n/27....】
  4. 随着gap的变小,组数会变小,每组里面的数值个数会变大。

    gap的值

  • 一个数无论是奇数还是偶数/2 最后都等于1
  • gap的值不是固定的,可以是gap/2或者gap/3+1
  • gap值无论是/2 /3,最后都必须==1 ,最后要直接插入排序
  • gap>1时时预排序,目的是让整体数值更加接近有序
  • gap == 1的时候就是直接插入排序,目的是让整体值有序。
  • gap的值越大,大的值更快的调到后面,小的值可以更快的调到前面,越不接近有序。
  • gap的值越小,大的值更慢的调到后面,小的值可以慢的调到前面,越接近有序。
  • gap的值不是固定的,gap的值是随着整体n的大小变化而变化的。
  • 随着gap的变小,组数会变小,每组里面的数值个数会变大。
  • 预排序gap的上一个值排完之后会对下一个值得排序调整次数产生影响。

  • 整体思路

  • 一趟:类似直接插入排序的一趟,间距从1变为gap
  • 一组:加入循环,完成一组的排序(类似直接插入排序整体)
  • 多组:加入三层嵌套循环/多组并排。(完成多组排序)(gap是多少就有多少组)
  • 整体:完成整个数组的排序(多次预排序直到最后插入排序gap=1)(n个值)gap=n(gap=gap/2或者gap=gap/3+1)

图解分析

  • gap是数值之间的间距值❗
  • gap=n(n是整个的数值个数)
  • gap=gap/2
  • gap=10/2=5
  • gap=5/2=2
  • gap=2/2=1
  • 注意:无论gap用gap/2或者gap/3+1或者其他最后gap的值必须为1,因为最后要进行直接插入排序,完成整体的排序。 

【1】预排序

为了理解,这里我们先把gap理解为固定值gap == 3是一个固定值。 假设n=11

单组排序

  • 一组一组排序
  • 三个嵌套循环
  • 控制起始位置i=j(0/1/2)
  • i=0(0/3/6)
  • i=1(1/4/7)
  • i=2(2/5)
  • i=0/3/6/1/4/7/2/5
  • 控制数组元素下标,防止越界i<n-gap(i<11-3=8)

//升序
//写法1:三层嵌套循环
void ShellSort(int* a, int n)
{
	//多组
	int gap = 3;
	for (int j = 0; j < gap; j++)
	{
        //每组
		for (int i = j; i < n - gap; i += gap)
		{
			int end = i;
			int tmp = a[end + gap];
			//一趟
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else//<=
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

多组并排

  • 多组并排
  • 两个嵌套循环
  • 控制起始位置i=0/1/2
  • i=0/1/2/3/4/5/6/7
  • 控制数组元素下标,防止越界i<n-gap(i<11-3=8)

//写法2
//多组并排
void ShellSort(int* a, int n)
{

	//多组
	int gap = 3;
	for (int i = 0; i < n - gap; i++)
	{
		int end = i;
		int tmp = a[end + gap];
		//一趟
		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + gap] = a[end];
				end -= gap;
			}
			else//<=
			{
				break;
			}
		}
		a[end + gap] = tmp;
	}
}

【2】直接插入排序

实际上如果整体的数量过大,gap为3是非常不合适的。所以,gap不可能为固定值,gap的取值是随着n变化的,所以gap有两种方式去取值。

关于gap取值 

  • gap=gap/2
  • gap=gap/3+1
  • 注意:无论gap用gap/2或者gap/3+1或者其他。最后gap的值必须为1,因为最后要进行直接插入排序,完成整体的排序。 
  • gap是几,就可以把整体分为几组。(除去gap = n的情况)(gap=gap/2或者gap=gap/3+1)
  • 分组和每组里面的元素个数的关系
  • gap = n(gap随着n的变换而变化,gap的值不固定)
  • gap/2(每次gap组,每组里面的元素个数:2,4,8......)*2 【n/2,n/4,n/8....】
  • gap/3+1 (每次gap组,每组里面的元素个数:3,9,27...)*2【n/3,n/9,n/27....】
  • 随着gap的变小,组数会变小,每组里面的数值个数会变大。
void ShellSort(int* a, int n)
{
	//整体
	int gap = n;
	while (gap > 1)
	{
		//每组
		//gap = gap / 2;
		gap = gap / 3 + 1;
        //..........
		}
	}
}

总代码实现

void ShellSort(int* a, int n)
{
	//整体
	int gap = n;
	while (gap > 1)
	{
		//每组
		//gap = gap / 2;
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			//一趟
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else//<=
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

时间复杂度

  • 希尔排序的时间复杂度O(N^1.3)
  • O(N^1.3)比O(N*logN)略慢,效率略低一点。
  • 希尔排序VS直接插入排序(秒入过万VS分入过万)
  • 预排序gap的上一个值排完之后会对下一个值得排序调整次数产生影响。
  • O(N^1.3)需要套用数学模型,统计学来计算,这里只是近似计算。记住最后结论即可。

🙂感谢大家的阅读,若有错误和不足,欢迎指正。下篇选择排序&堆排序。大家新年快乐!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/395006.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[力扣 Hot100]Day29 删除链表的倒数第 N 个结点

题目描述 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 出处 思路 两个指针间隔n&#xff0c;一趟遍历解决。 代码 class Solution { public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* phead;ListNode* …

计算机网络基础入门指南

文章目录 网络分层模型OSI七层模型及其作用TCP/IP四层模型及作用为什么网络需要分层&#xff1f; 常见的网络协议应用层常见的协议传输层常见的协议网络层常见协议 从输入URL到页面展示的过程HTTP常见的状态码HTTP与HTTPS的区别HTTP是不保存状态的协议&#xff0c;如何保存用户…

激光条纹中心线提取算法FPGA实现方案

1 概述 激光条纹中心线提取是3D线激光测量领域一个较为基础且重要的算法。目前&#xff0c;激光条纹中心线提取已有多种成熟的算法&#xff0c;有很多相关的博客和论文。 激光条纹中心线提取的真实意义在于工程化和产品化的实际应用&#xff0c;而很多算法目前只能用于学术研究…

(五)【Jmeter】使用代理录制HTTP脚本操作步骤及注意事项

前置信息 软件版本Jmeter5.6.3服务网址备注drupalhttp://192.168.88.88:18080/(二)【Jmeter】专栏实战项目靶场drupal部署 用户名密码test1test1test2test2实操记录 1、启动jmeter,操作顺序见下图 2、在视图面板添加如下信息,点击开始

简单一招,教你高校管理校园门禁!

在当今社会&#xff0c;随着城市化和科技的不断发展&#xff0c;人们对安全管理的需求日益增加。门禁监控系统作为一种现代化、智能化的安全管理工具&#xff0c;正逐渐成为各种场所的必备设施。 客户案例 企业办公大楼 北京某大型企业在其办公大楼部署了泛地缘科技推出的门禁…

PyCharm - Script parameters (脚本参数)

PyCharm - Script parameters [脚本参数] References Run -> Edit Configurations… -> Run/Debug Configurations -> Configuration -> Script parameters 命令行&#xff1a; python display_yolo_log.py ./person_training_log/person_train_log_DIMM40_stdout…

数据库应用:kylin 部署 达梦数据库DM8

目录 一、实验 1.环境 2.部署前规划 3.部署达梦数据库DM8 4.创建数据库及数据库事例管理 5.达梦数据库的基本操作 二、问题 1.xhost命令报错 2.执行安装程序DMInstall.bin 报错 3.解压安装程序报错 4.安装程序找不到文件 5.图像化界面打不开 6.安装内存太小 7.打开…

真·DRC SELECT CHECK

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 相关文章链接: Calibre DRC的运行和常见语法 以往做Calibre DRC迭代检查时​,仅需要检查少数项目通常会用到DRC SELECT CHECK命令,具体用法见上面往期文章链接,图形界面运行时仅仅加上DRC SELE…

计算机专业必看的几部电影

计算机专业必看的几部电影 在计算机专业的学习和工作中&#xff0c;电影作为一种娱乐形式&#xff0c;也可以给我们带来不少启发和思考。以下是几部计算机专业必看的电影推荐&#xff0c;从技术与主题、职业与人生等方面进行分析。 1. 《黑客帝国》&#xff08;The Matrix&am…

深入探讨Lambda表达式转换为委托类型的编译过程

了解了&#xff0c;如果要深入探讨Lambda表达式转换为委托类型的编译过程&#xff0c;我们需要关注C#编译器如何处理这个转换。这个过程涉及到编译时的类型推断、匿名方法的创建&#xff0c;以及生成对应的委托实例。我们来更详细地分析这个过程&#xff1a; 编译阶段 1. 解…

JVM--- 垃圾收集器详细整理

目录 一、垃圾收集需要考虑的三个事情&#xff1a; 二、垃圾回收针对的区域 三、如何判断对象已死 1.引用计数算法&#xff1a; 2.可达性分析算法 四、引用 五、生存还是死亡&#xff1f; 六、回收方法区 七、垃圾收集算法 1.分代收集理论 2.标记-清除算法 3.标记-复制算…

java以及android类加载机制

类加载机制 一、Java类加载机制 java中&#xff0c;每一个类或者接口&#xff0c;在编译后&#xff0c;都会生成一个.class文件。 类加载机制指的是将这些.class文件中的二进制数据读入到内存中并对数据进行校验&#xff0c;解析和初始化。最终&#xff0c;每一个类都会在方…

【 JS 进阶 】原型对象、面向对象

目标 了解构造函数原型对象的语法特征&#xff0c;掌握 JavaScript 中面向对象编程的实现方式&#xff0c;基于面向对象编程思想实现 DOM 操作的封装。 了解面向对象编程的一般特征掌握基于构造函数原型对象的逻辑封装掌握基于原型对象实现的继承理解何为原型链及其作用能够处理…

文物保护系统守护历史岁月,成都青铜展科技闪耀

一、“吉金万里-中国西南青铜文明展”隆重开幕 1月27日&#xff0c;“吉金万里-中国西南青铜文明展”在成都金沙遗址博物馆向公众开放&#xff0c;奉上一场精彩的青铜文明“盛宴”。本次展览汇集了中国西南地区32家文博单位&#xff0c;以青铜器为代表的294件经典文物&#xf…

人工智能_普通服务器CPU_安装清华开源人工智能AI大模型ChatGlm-6B_001---人工智能工作笔记0096

使用centos安装,注意安装之前,保证系统可以联网,然后执行yum update 先去更新一下系统,可以省掉很多麻烦 20240219_150031 这里我们使用centos系统吧,使用习惯了. ChatGlm首先需要一台个人计算机,或者服务器, 要的算力,训练最多,微调次之,推理需要算力最少 其实很多都支持C…

腾讯云助力酒店IT系统上云,实现出海业务的双重优势

潮起潮涌&#xff0c;随着时代浪潮的翻涌&#xff0c;生活处处可见是巨大的变化&#xff0c;衣食住行都有了更多更大的需求&#xff0c;出门旅游观赏当地风景品尝特色美食的前提是要住好&#xff0c;只有休息好了才有更多的精力去游玩。酒店系统的升级上云让登记变得更加便捷&a…

C# 12 中新增的八大功能你都知道吗?

一、主构造函数 在 Visual Studio 2022 版本 17.6 预览版 2 中引入。 从 C# 12 开始&#xff0c;可以在类和结构中声明主构造函数。主构造函数参数都在类的整个主体的范围内。为了确保显式分配所有主构造函数参数&#xff0c;所有显式声明的构造函数都必须使用 this() 语法调用…

基于SpringBoot的药品管理系统

基于SpringBoot的药品管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 药品详情 个人中心 员工界面 管理员界面 摘要 随着医疗技术的不断发展和人们健…

电子元器件基础7---集成电路

二极管三极管再往上就是四极管、五极管么?不,四极管还有但是我没用过。再往上我们需要学习各种阻容二极管和三极管的组合,也就是今天要介绍的集成电路,它的集成度从几个晶体管组合的元器件到上亿个晶体管组成的CPU,器件数量越多集成度越高同时其功能也更加复杂。 在这里我…

【Java EE初阶十四】网络编程TCP/IP协议(一)

1. 网络编程 通过网络&#xff0c;让两个主机之间能够进行通信->就这样的通信来完成一定的功能&#xff0c;进行网络编程的时候&#xff0c;需要操作系统给咱们提供一组API&#xff0c;通过这些API来完成编程&#xff1b;API可以认为是应用层和传输层之间交互的路径&#xf…