【数据结构初阶】C语言从0到1实现希尔排序

news2025/7/11 1:54:57

 🌟hello,各位读者大大们你们好呀🌟

🍭🍭系列专栏:【数据结构初阶】

✒️✒️本篇内容:深入剖析希尔排序

🚢🚢作者简介:计算机海洋的新进船长一枚,请多多指教( •̀֊•́ ) ̖́-

📡📡同期数据结构文章:【数据结构初阶】C语言从0到1带你了解直接插入排序

前言

需要直接插入排序的基础,才能更好的理解文章,详情可见上栏同期数据结构文章

希尔排序法又称缩小增量法,希尔排序法的基本思想是:

先选定一个整数,把待排序文件中所有数分成 gap 个组,所有距离为 gap 的数分在同一组内,并对每一组内的数先进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

1.先进行预排序,将一组数分为 gap 组,对间隔为 gap 的数进行直接插入排序

void ShellSort(int* a, int n)
{
    int gap;
	int end;
	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;
}

至此,我们已经完成了一次插入排序,也就是可以将红色组的9、5变得有序。接下来就是加入循环,完成多次插入排序,使间隔为 gap 的数组成的数组有序,以下图红色组为例,就是将 9,5,8,5 变得有序


 2.加入循环,完成多次插入排序,使间隔为 gap 的数组成的数组有序

  • 增加一个for循环,对红色组进行排序
  • n为数组长度,i < n - gap 避免越界(若 i<n,end可以指到数组尾部,tmp将出界)
		int gap = 3;
        for (int i = 0; i < n - gap; i += gap)
		{
			// [0,end] 插入 end+gap [0, end+gap]有序  -- 间隔为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;
		}

至此,我们第一组(红色组)就排完了,数组将会变成 5,1,2,5,7,4,8,6,3,9


3.再加一组循环,循环 gap 次,使 gap 组的数都变得有序(以下数组为例,就是让红、蓝、绿组都变得有序)

  • 创建一个for循环,对不同颜色组排序
  • 在这里,j = 0,排红色组;j = 1,排蓝色组;j = 2,排绿色组

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)
		{
			// [0,end] 插入 end+gap [0, end+gap]有序  -- 间隔为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;
		}
	}	


4.算法优化,三层循环变两层循环(时间复杂度相同,所以写上面的这种也行)

  • 只需要将第二层循环 i += gap 变为  ++i 即可,可以理解红组,然后红组9,5拍完,蓝组1,7排,蓝组排完绿组2,4排,以此类推。
  • 不同于上面先给红组排完,再给蓝组排,蓝组排完,再给绿组排

void ShellSort(int* a, int n)
{
	int gap = 3;
	for (int i = j; i < n - gap; ++i)
	{
		// [0,end] 插入 end+gap [0, end+gap]有序  -- 间隔为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;
	}
}	

至此,我们已经完成了预排序, 完成了数组接近有序的目标,大大降低了对每个数直接排序的时间复杂度


5.对每个数进行直接插入排序,我们可以通过控制 gap 的值,来区分预排序和直接插入排序

  • 当 gap == 1 时,这个算法就是直接插入排序
  • 我们可以设 gap = n,再通过循环,不断缩小gap的值,不断预排序,使其最后变为直接插入排序
  • 通过大量实验我们可以得出,gap / 2,或者 gap / 3+1 时,预排序的效果最好
  • gap / 3+1 是为了保证除到最后的数=1,如3/3+1=1,4/3+1=2,2/3+1=1
	// gap > 1  预排序
	// gap == 1 直接插入排序

// O(N^1.3)
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//gap = gap / 2;
		gap = gap / 3 + 1;    //+1是为了保证除到最后的数=1

		// [0,end] 插入 end+gap [0, end+gap]有序  -- 间隔为gap的数据
		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;
		}
	}
}


6.我们将上述代码补充完整,进行一次实验

sort.h

#include <stdio.h>
#include <stdlib.h>

void ShellSort(int* a, int n);

 sort.c

void PrintArray(int* a, int n)
{
	for (int i = 0; i < n; ++i)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}

	// gap > 1  预排序
	// gap == 1 直接插入排序

// O(N^1.3)
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//gap = gap / 2;
		gap = gap / 3 + 1;    //+1是为了保证除到最后的数=1

		// [0,end] 插入 end+gap [0, end+gap]有序  -- 间隔为gap的数据
		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;
		}
	}
}

test.c

void TestShellSort()
{
	//int a[] = { 9,8,7,6,5,4,3,2,1,0 };
	int a[] = { 34, 56, 25, 65, 86, 99, 72, 66 };
	ShellSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}


int main()
{
    TestShellSort();
	return 0;
}

结果如下  


希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定,我们可以使用Knuth的取值或者大概平均值O(n^1.3),对比下略差于O(n*logn)的算法
  4. 稳定性:不稳定

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


🌹🌹希尔排序排序大概就讲到这里啦,博主后续会继续更新更多数据结构的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪 

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

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

相关文章

SpringBoot中的AOP使用

文章目录SpringBoot中的AOP使用1.AOP介绍2. AOP 编程术语2.1切面&#xff08;Aspect&#xff09;2.2连接点&#xff08;JoinPoint&#xff09;2.3切入点&#xff08;Pointcut&#xff09;2.4目标对象&#xff08;Target&#xff09;2.5通知&#xff08;Advice&#xff09;3.切入…

【经济调度】基于蝙蝠算法实现电力系统经济调度附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

【Qt按钮基类】QAbstractButton[ 所有按钮基类 ]

【Qt按钮基类】QAbstractButton[ 所有按钮基类 ]Qt开启-》按钮基类 QAbstractButton一、setText (设置文本)二、text&#xff08;获取文本&#xff09;三、setIcon&#xff08;设置图标&#xff09;四、icon&#xff08;获取图标&#xff09;五、 iconSize &#xff08;获取图标…

体系结构29_多处理机的互联网络

互连网络是将集中式系统或分布式系统中的结点连接起来所构成的网络&#xff0c;这些结点可能是处理器、存储模块或者其它设备&#xff0c;它们通过互连网络进行信息交换。在拓扑上&#xff0c;互连网络为输入和输出两组结点之间提供一组互连或映象&#xff08;mapping&#xff…

通力科技通过注册:9个月营收3.4亿 项献忠家族色彩浓厚

雷递网 雷建平 11月25日浙江通力传动科技股份有限公司&#xff08;简称&#xff1a;“通力科技”&#xff09;日前通过注册&#xff0c;准备在深交所创业板上市。通力传动计划募资3.45亿元。其中&#xff0c;2亿元用于新增年产5万台工业减速机智能工厂技改项目&#xff0c;5041…

成为一名厉害的程序员,需要哪些必备知识

程序员在入职时&#xff0c;大部分互联网公司都会进行基础知识的考察&#xff0c;基础知识的重要性不言而喻。计算机基础知识对程序员来说很重要。计算机核心基础知识方面&#xff0c;算法、数据结构、组成原理、网络等涉及到的基础知识一定要彻底掌握&#xff0c;牢牢记住并融…

[附源码]java毕业设计智能视频推荐网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

3.90 OrCAD软件Annote命令下的每个选项的含义是什么?OrCAD软件Title Block中的原理图页数如何进行增加?

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

【自学前端】HTML篇已完结(附14节视频)

I have a dream,Front end development will not require additional training. 目录 内容预览 通过这里找视频&#xff1a; 1、内容仍然有所欠缺 2、目前以0基础再实战为主 3、目前未包含面试题 4、下一步的计划 5、希望收到反馈 内容预览 △ 目前纯HTML篇课程已经完成…

【项目实战:核酸检测平台】第三章 利其器

第三章 利其器 摘要:俗话说的好工欲善其事&#xff0c;必先利其器&#xff0c;框架搭的好&#xff0c;开发起来很舒服&#xff0c;搭的不好&#xff0c;开发起来就很痛苦。 一个程序员只会写业务代码&#xff0c;最多算是个码农&#xff0c;搭框架的本事、遇到难题的解决能力…

Docker学习(5)—— 在Docker上安装软件

一. 安装Tomcat 1. 下载最新版 (1) 拉取Tomcat镜像 docker pull tomcat (2) 查看是否拉取到Tomcat镜像 docker images tomcat (3) 创建Tomcat容器并启动 docker run -d -p 8080:8080 tomcat 这时访问tomcat首页报404错误&#xff0c;有以下两个原因&#xff1a;①防火…

[计算机毕业设计]大数据的B站数据分析与可视化

目录 前言 课题背景和意义 实现技术思路 数据爬取 数据可视化 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研…

为什么 NGINX 的 reload 不是热加载?

作者&#xff1a;刘维 这段时间在 Reddit 看到一个讨论&#xff0c;为什么 NGINX 不支持热加载&#xff1f;乍看之下很反常识&#xff0c;作为世界第一大 Web 服务器&#xff0c;不支持热加载&#xff1f;难道大家都在使用的 nginx -s reload 命令都用错了&#xff1f; 带着这个…

入职阿里必会199道SpringCloud面试题,你能掌握多少?

前言 Spring Cloud 自 2016 年 1 月发布第一个 Angel.SR5 版本&#xff0c;到目前 2020 年 3 月发布 Hoxton.SR3 版本&#xff0c;已经历经了 4 年时间。这 4 年时间里&#xff0c;Spring Cloud 一共发布了 46 个版本&#xff0c;支持的组件数从 5 个增加到 21 个。 Spring C…

linux用户及用户组的分类、管理

一、分类 1.用户和用户组分类 &#xff08;1&#xff09;用户分类 超级用户&#xff08;root&#xff09;——它具有一切权限&#xff0c;只有进行系统维护&#xff08;例&#xff1a;建立用户&#xff09;或其他必要情形下才用超级用户登录&#xff0c;以避免系统出现安全问…

Qt程序打包成一个单独exe的方法

目录 Qt程序打包成一个单独exe的方法 程序发布 程序打包 问题 Qt程序打包成一个单独exe的方法 Qt程序发布及打包&#xff0c;同时修改可执行文件的图标。本教程使用Qt自带的 windeployqt 工具外加Enigma Virtual Box打包工具。首先需要知道的是&#xff0c;Qt程序发布需要的…

【MM小贴士】物料主数据的中止与后继(3)

话不多说&#xff0c;直接上3&#xff0c; 前两篇的blog可以参考&#xff1a; 【MM小贴士】物料主数据的中止与后继(1)_竹大的博客-CSDN博客https://yanshoushuai.blog.csdn.net/article/details/125660495【MM小贴士】物料主数据的中止与后继(2)_竹大的博客-CSDN博客https:/…

QT 事件处理

03 Qt中是事件处理_哔哩哔哩_bilibili 1&#xff0c;新加mylabel文件&#xff0c;并 修改mylabe的基类QLabel 2 label提升为类 3&#xff0c;鼠标事件 myLabel.h #ifndef MYLABEL_H #define MYLABEL_H#include <QLabel>class myLabel : public QLabel {Q_OBJECT public…

TCP三次握手四次挥手简介

TCP三次握手四次挥手简介 图解三次握手、四次挥手 建立连接&#xff1a;三次握手 关闭连接&#xff1a;四次挥手 上图传递过程中出现的几个字符&#xff08;SYN,ACK,FIN,seq,ack&#xff09;各代表什么意思 SYN&#xff0c;ACK&#xff0c;FIN存放在TCP的标志位(标志位一共有…

【设计模式】设计模式的七大原则

目录标题4. 设计模式的七大原则4.1 开闭原则&#xff08;对扩展开发&#xff0c;对修改关闭&#xff1a;需要接口和抽象类来实现&#xff09;Demo: 搜狗输入法 的皮肤设计4.2 里氏替换原则&#xff08;任何基类可以出现的地方&#xff0c;子类一定可以出现&#xff1a;尽量不要…