希尔排序算法

news2024/10/4 4:20:13

目录

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)需要套用数学模型,统计学来计算,这里只是近似计算。记住最后结论即可。

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

产品经理学习-产品运营《流程管理》

如何进行流程管理 信息可视化 甘特图-流程管理思维导图-方案讨论原型图-活动文档 明确责任制 分工明确&#xff0c;关键环境有主负责人通过时间倒推督促管理 沟通技巧 明确共同利益以结果激励做好信息同步 如何进行监控活动效果 监控活动的效果是要监控数据 活动每个环境的…

MySQL学习记录——십일 索引

文章目录 1、了解索引2、聚簇、非聚簇索引3、操作1、主键索引2、唯一键索引3、普通索引4、注意事项 4、全文索引 1、了解索引 MySQL服务器是在内存中的&#xff0c;所有数据库的CURD操作都是在内存中进行&#xff0c;索引也是如此。索引是用来提高性能的&#xff0c;它通过组织…

[嵌入式系统-16]:RT-Thread -2- 主要功能功能组件详解与API函数说明、API参考手册入口

目录 一、RT-Thread主要功能组件 二、内核组件 2.1 概述 2.2 API 三、设备驱动 3.1 概述 3.2 API 四、通信组件 4.1 概述 4.4 API 五、网络组件 5.1 概述 5.2 API 5.3 补充&#xff1a;MQTT协议 六、文件系统 6.1 概述 6.2 API 七、GUI 组件 7.1 概述 7.2 …

进程终止与进程等待

fork 函数 fork 函数是 Linux 中一个非常重要的函数&#xff0c;它的作用是从已存在的进程中创建一个新进程。这个新进程就是当前进程的子进程。 fork() 函数使用方法&#xff1a;它在头文件 #include <unistd.h> 中&#xff0c;函数原型为 pid_t fork(void); 用一个…

CMNet:Contrastive Magnification Network for Micro-Expression Recognition 阅读笔记

AAAI 2023的一篇文章&#xff0c;东南大学几位老师的工作&#xff0c;用于做微表情识别中的运动增强工作&#xff0c; 以下是阅读时记录的笔记。 摘要&#xff1a; However,existing magnification strategies tend to use the features offacial images that include not onl…

Minio通过Url直接访问附件

1、修改桶策略为public 2、http://locahost:9000/桶名/文件名即可 访问该文件&#xff0c;自己浏览 http://127.0.0.1:9000/netcore/netcore/9d4a526b-a477-46a3-90c7-a668354e3b46.png

C语言每日一题(59)左叶子之和

题目链接 力扣网404 左叶子之和 题目描述 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别是 9 和 15&#xff0c;所以返回 2…

【C++航海王:追寻罗杰的编程之路】vector

目录 1 -> vector的介绍及使用 1.1 -> vector的介绍 1.2 -> vector的使用 1.2.1 -> vector的介绍 1.2.2 -> vector iterator的使用 1.2.3 -> vector空间增长问题 1.2.4 -> vector的增删查改 1.2.5 -> vector迭代器失效问题 2 -> vector的深…

K8s进阶之路-控制器无状态服务:

RC/RS/Deployment 控制器 deployment无状态&#xff08;最常用&#xff09;&#xff1a; nginx和Apache statefulset有状态&#xff1a; mysql和redis damonset初始化 job一次性任务 cronjob任务计划 1无状态&#xff1a;不会对本地环境产生依赖如&#xff1a;nginx和Apache …

Docker详解及使用

文章目录 为什么要用docker为什么会出现容器Docker 是什么容器是什么虚拟化是什么Docker 和 虚拟化的区别Docker 容器有几种在状态什么是仓库什么是镜像什么是容器仓库、镜像、容器的关系常用的 Docker 命令如何把主机的东西拷贝到容器内部如何让容器随着 Docker 服务启动而自动…

八、右侧下部页面内容区域

内容区可直接放置router-view占位子路由展示位置 所有内容区路由是layout的子路由&#xff0c;子路由需要在父路由中使用router-view占位才能显示app.vue是所有其他组件的父view/router&#xff0c;router里的父子关系通过来展现。所以在app.vue也要router-view标签 也可拆成组…

⭐北邮复试刷题LCR 012. 寻找数组的中心下标__前缀和思想 (力扣119经典题变种挑战)

LCR 012. 寻找数组的中心下标 给你一个整数数组 nums &#xff0c;请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和等于右侧所有元素相加的和。 如果中心下标位于数组最左端&#xff0c;那么左侧数之和视为 0 &#xff0c;因为…

SpringMVC 的参数绑定之list集合、Map

标签中name属性的值就是pojo类的属性名 参数绑定4 list [对象] <form action"teaupd.do" method"post"> <c:forEach items"${list}" var"tea" varStatus "status"> 教师编号&#xff1a;<input…

【SV的面向对象 SV的类_2024.01.02】

OOP术语 OOP&#xff1a;object oriented programming Class类&#xff1a;包含变量和子程序的基本构建块 Object对象&#xff1a;类的一个实例 Handle句柄&#xff1a;指向对象的指针 Property属性&#xff1a;存储数据的变量&#xff1b;在V中&#xff0c;可以是wire或reg类…

⭐北邮复试刷题LCR 034. 验证外星语词典__哈希思想 (力扣119经典题变种挑战)

LCR 034. 验证外星语词典 某种外星语也使用英文小写字母&#xff0c;但可能顺序 order 不同。字母表的顺序&#xff08;order&#xff09;是一些小写字母的排列。 给定一组用外星语书写的单词 words&#xff0c;以及其字母表的顺序 order&#xff0c;只有当给定的单词在这种外…

莱卡云怎么样?简单测评下莱卡云韩国CN2云服务器

莱卡云服务器厂商&#xff0c;国内持证企业服务器商家&#xff0c;运作着香港、美国、韩国、镇江、日本、绍兴、枣庄、等数据中心的云服务器、独立服务器出租、设备托管、CDN等业务。今天为大家带来的是莱卡云韩国CN2服务器的详细评测&#xff0c;该云服务器的数据中心位于韩国…

大语言模型学习路线:从入门到实战

大语言模型学习路线&#xff1a;从入门到实战 在人工智能领域&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;正迅速成为一个热点话题。 本学习路线旨在为有基本Python编程和深度学习基础的学习者提供一个清晰、系统的大模型学习指南&#xff0c;…

阿里云服务器“镜像”全方面解析

阿里云服务器镜像怎么选择&#xff1f;云服务器操作系统镜像分为Linux和Windows两大类&#xff0c;Linux可以选择Alibaba Cloud Linux&#xff0c;Windows可以选择Windows Server 2022数据中心版64位中文版&#xff0c;阿里云服务器网aliyunfuwuqi.com来详细说下阿里云服务器操…

辽宁博学优晨教育科技有限公司视频剪辑培训靠谱吗?

在数字媒体日益繁荣的今天&#xff0c;视频剪辑已成为一项炙手可热的技能。不少培训机构纷纷涉足这一领域&#xff0c;辽宁博学优晨教育科技有限公司便是其中之一。然而&#xff0c;面对众多的选择&#xff0c;很多人不禁要问&#xff1a;辽宁博学优晨教育科技有限公司的视频剪…

【二十八】springboot整合logback实现日志管理

本章节是记录logback在springboot项目中的简单使用&#xff0c;本文将会演示如何通过logback将日志记录到日志文件或输出到控制台等管理操作。将会从以下几个方面进行讲解。最后实现将特定级别的特定日志保存到日志文件。 一、依赖 <dependency><groupId>ch.qos.l…