希尔排序原理

news2025/1/11 1:45:23

目录:

一、希尔排序与插入排序

        1)希尔排序的概念

        2)插入排序实现   

二、希尔排序实现


一、希尔排序与插入排序

        1)希尔排序的概念

        希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。

        希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。


        2)插入排序实现   

        既然希尔排序是插入排序的优化,那么我们有必要先了解一下插入排序的过程,基本操作是将需要进行排序的元素插入到已排序区当中,这样每次插入都会使已排序区长度加一。

        直观的看,插入排序的操作就和我们在打扑克牌时一样,我们默认将小的或者大的往一边插进去,插入排序也是如此。

         1、我们从第二个元素开始插入排序,因为这样左边只有一个数,必然有序,我们把左边的称为已排序区,右边的称为待排序区。

        2、将待排序区的第一个元素向已排序区插入,将其与已排序区元素从后向前比较,将其插入到合适位置,已排序区元素个数+1。

        3、然后待排序区重复2的步骤向已排序区从后往前比较,找到合适位置插入。

        4、 继续将待排序区元素插入到已排序区,当待排序区元素为0时,这组数据就已经排序完成。

        我们明白了插入排序的过程,接下来就是实现插入排序了,我们先来分析,插入排序中第一个元素(0位置处)本来就是有序的,所以我们直接从第二个元素开始操作(1位置处)。

        1、定义待排序区的首元素下标为end,用tmp记录下end下标的元素,将tmp与已排序区元素进行比较,发现小于5,则将待排序区的元素插入到首元素位置。

        2、已排序区数组元素加一,待排序区首元素变为3,end也变为3的下标,tmp记录此元素的值,将tmp与已排序区元素进行比较,首先与5比较,小于5。

         3、再跟1比较发现大于1,那么这个值就插入在1和5之间,已排序元素加一,待排序数组元素减一。

        4、一直刷新end与tmp值,与已排序区进行从右往左的比较,比较到合适的位置才进行插入,而不是每次比较都插入元素。

        时间复杂度最坏情况下为 O(N^2),此时待排序列为逆序或者说接近逆序最好情况下为 O(N)此时待排序列为升序,或者说接近升序。平均为O(N^2)

        空间复杂度:没有额外使用空间,所以空间复杂度为 O(1)

        代码实现:

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

void InsertSort(int *a, int len)//插入排序
{
	int i = 0;
	for(i = 1 ; i < len ; i++)//从下标为1的位置进行插入排序
	{
		int end = i;//用end记录待排序区的首元素下标
		int tmp = a[end];//用tmp记录待排序区首元素的值
		while(end > 0)//保证不越界tmp就一直往前进行比较,找到合适的位置break
		{
			if(a[end - 1] > tmp)
			{
				a[end] = a[end - 1];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end] = tmp;//最后在将tmp值放在end的下标下
	}
}

void Print(int *a, int len)//打印数组元素
{
	int i = 0;
	for(i = 0 ; i < len ; i++)
	{
		printf("%3d",a[i]);
	}
	printf("\n");
	return;
}

void Test()//测试
{
	int a[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
	int len = sizeof(a) / sizeof(int);
	InsertSort(a, len);
	Print(a, len);
	return;
}

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

运行结果:


二、希尔排序实现

         希尔排序法又称为缩小增量法。希尔排序法的基本思想是:首先选定一个整数,把待排序文件中所有记录分成gap个组(增量),所有距离为gap的数据记录在同一组内,并对每一组内的记录进行排序。然后,再取gap/2个组(缩小增量),重复上述分组和排序的工作。当gap == 1时所有记录在统一组内排好序

        注希尔排序缩小增量在数学上是个难题,大家经常用的就是gap/2。

         我们有这样一个数组:a[] = {6, 1, 5, 2, 4, 8, 3, 7, 9}。我们对这个数组进行排序,首先假设设置gap的值为3,那么这组数就会分为三组:

        接下来控制这三组,每组分别进行插入排序,结果为:

        那么gap为3时的所有组已经排完了,接下来就该缩小增量了,gap /= 2,gap == 1:

        知晓了希尔排序是如何进行数据管理的,下面来看看具体的操作是如何完成的:

        1、首先, 我们需要对gap进行控制,在gap>0范围内,每次分组后的所有组排完序之后都要除以二,可以用while循环来控制gap的大小:

void ShellSort(int *a, int n)
{
	assert(a);
	int gap = n;
	int i = 0;
	while(gap > 1)
	{
		if(gap > 1)
		gap /= 2;
        //..分完组后的预排序	    	
    }
}

        2、我们已经将缩小增量设置好了,接下来只需要把每次分完组都进行排序,也就是预排序。如何进行预排序呢?既然希尔排序是插入排序的优化,我们不妨以插排的思路对希尔预排序进行调整。

        用for循环对所有数据进行预排序,值得注意的是这里不会像插排那样循环到n,我们只需要限制在n - gap 的范围就行了,例如上图:

        这个数组从3往后就不需要排了,因为在每一组的排序中最后一个值都是被拍过序的,没必要再次进行一次排序,总共为n个数据,那么就是只需要n - gap - 1个数据进行排序。则:

void ShellSort(int *a, int n)
{
	assert(a);
	int gap = n;
	int i = 0;
	while(gap > 1)
	{
		if(gap > 1)
		gap /= 2;
        for(i = 0 ; i < n - gap ; i++)//控制n - gap数据进行预排序
        {
            //具体排序过程...
        }
    }
}

         3、其实预排序的实现和直接插入排序的过程几乎是完全相似,前面也说了当希尔排序的缩小增量为1时,和插入排序没区别,也就是说,插入排序每次都对相邻的数据处理,而希尔排序是将分好的组看成新的数组,例如上面数据的6, 2, 3为一组,我们可以看成其他的数据不存在,只有这一组存在,那么对于这一组而言,希尔排序就是插入排序,将上图的三组都排完序,这一趟预排序就算完成了。

        与插入排序相同,定义一个end记录当前元素下标,定义一个tmp记录a[end + gap]处的值,为什么不是a[end]处的值?可别忘了第一个值是默认有序的,所以要从第二个值向前比较,当end对应的值要大于tmp那么就将end处的值赋给下一个位置,也就是end+gap处,当不满足end处的值大于end+gap时,代表前面已经没有比自己大的值了,直接break,最后在循环结束的时候记得将a[end + gap]之前被覆盖的地方重新赋值:

void ShellSort(int *a, int n)
{
	assert(a);
	int gap = n;
	int i = 0;
	while(gap > 1)
	{
		if(gap > 1)
		gap /= 2;
		for( i = 0; i < n - gap; i++)//对n组数据进行n - gap次预排序
		{
			int end = i;
			int tmp = a[gap + end];
			while(end >= 0)//当end >= 0时候对每组进行预排序
			{
				if(tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
	return;
}

        这样希尔排序就完成了,其实在希尔排序的过程中,或许你还有疑问,为什么for循环这里是连续的?不是进行分组了吗?其实你仔细想想, 我们还是以上面gap==3为例,首先是第一个数据,就是对第一组的首个数据进行排序,当到了第二个数据的时候,就是对第二组首个数据进行排序,但是因为有gap的控制,这两组数据其实是互不影响的,所以连续的遍历数据进行预排序也是没有问题的。

        总结希尔排序的特性:

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

        2、当gap > 1时,都是预排序,目的是让数组更接近有序,当gap==1时,将前面预排序的结果进行直接插入排序而完成排序。

        时间复杂度O(NlogN)(近似),因为增量问题并不能准确得出时间复杂度。

        空间复杂度:没有开额外的空间,所以空间复杂度为O(1)

以下是希尔排序的完整代码:

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

void ShellSort(int *a, int n)
{
	assert(a);
	int gap = n;
	int i = 0;
	while(gap > 1)
	{
		if(gap > 1)
		gap /= 2;
		for( i = 0; i < n - gap; i++)//对n组数据进行n - gap次预排序
		{
			int end = i;
			int tmp = a[gap + end];
			while(end >= 0)//当end >= 0时候对每组进行预排序
			{
				if(tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
	return;
}

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

int main()
{
	int a[] = {5,6,1,2,7,4,8,3,9};
	int len = sizeof(a) / sizeof(int);
	ShellSort(a, len);
	Print(a, len);
	return 0;
}


如果这篇文章对你有帮助的话,还望各位佬能多多三连~~[doge][玫瑰] 

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

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

相关文章

Python进阶教程:pandas数据分析实践示例总结

文章目录 前言一、分析数据文件二、数据预处理关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资料六、Python兼职渠道 前言 在近日的py…

RestTemplate配置和使用

在项目中&#xff0c;如果要调用第三方的http服务&#xff0c;就需要发起http请求&#xff0c;常用的请求方式&#xff1a;第一种&#xff0c;使用java原生发起http请求&#xff0c;这种方式不需要引入第三方库&#xff0c;但是连接不可复用&#xff0c;如果要实现连接复用&…

武汉凯迪正大—电能质量分析仪功能介绍

功能介绍&#xff1a; 测试功能&#xff1a; 波形实时显示&#xff08;4路电压/4路电流&#xff09;&#xff1b;电压和电流真有效值&#xff1b;电压直流成份&#xff1b;电流和电压峰值&#xff1b;电流和电压一段时间内的最大/最小值&#xff1b;相量图显示&#xff1b;各相…

深入浅出理解ResNet网络模型+PyTorch实现

温故而知新&#xff0c;可以为师矣&#xff01; 一、参考资料 原始论文&#xff1a;Identity Mappings in Deep Residual Networks 原论文地址&#xff1a;Deep Residual Learning for Image Recognition ResNet详解PyTorch实现 PyTorch官方实现ResNet 【pytorch】ResNet18、…

10道高频Vuex面试题快问快答

※其他的快问快答&#xff0c;看这里&#xff01; 10道高频Qiankun微前端面试题快问快答 10道高频webpack面试题快问快答 20道高频CSS面试题快问快答 20道高频JavaScript面试题快问快答 30道高频Vue面试题快问快答 面试中的快问快答 快问快答的情景在面试中非常常见。 在面试过…

凡泰极客亮相香港金融科技周,投身大湾区数字化建设

11月2-3日&#xff0c;作为全球性的金融科技盛会——香港金融科技周2023于香港会展中心隆重开幕。大会云集全球500多家金融机构及金融科技企业参展&#xff0c;吸引超过3万余人次相关人士参会。 凡泰极客作为中国领先的金融科技企业受邀参会&#xff0c;吸引了多领域专家、投资…

php加密解密的用法(对称加密,非对称加密)

加密和摘要的区别 ***摘要&#xff1a;是从已知的数据中&#xff0c;通过摘要计算出一个值&#xff0c;一个数据对应一个或多个摘要的值 *** 比如&#xff1a;md5 和 sha1 sha256 hash 就是得到一个特定的值 &#xff0c;同一个数据得到的md5 是一样的&#xff0c;不会改变的 比…

BeanUtils.copyProperties浅拷贝的坑你得知道?

今天想写一篇文章&#xff0c;主要关于深拷贝和浅拷贝相关的&#xff0c;主要是最近写代码的时候遇到一个BUG&#xff0c;刚好涉及到浅拷贝导致的问题。 问题背景 现在有一个需要是需要修改门店信息&#xff0c;门店也区分父门店和子门店&#xff0c;父门店被编辑更新是需要通过…

数据中台之数据分析

效果界面 技术方案 Notebook集成 在您的数据平台上,创建一个能够与Jupyter Notebook通讯的服务。通过Jupyter Notebook的HTTP API与Notebook实例进行交互,执行代码、获取输出等。用户界面 在数据开发/数据分析的代码框右上方,添加一个机器人样式的图标,用户点击后可以调起…

很多个pdf怎么合并在一起?

很多个pdf怎么合并在一起&#xff1f;作为一个办公室的伙伴&#xff0c;对于PDF格式肯定不会陌生。它强大的功能为我们的工作提供了许多便利。由于PDF文件格式的稳定性和安全性较高&#xff0c;我们通常在工作或学习中使用它来传输文件&#xff0c;很多人都喜欢将办公文件都做成…

linux系统下读取当前硬盘的温度

这个其实很简单&#xff0c;借助于smartctl工具&#xff08;Ubuntu默认安装好了&#xff09;&#xff0c;标红的部分就是当前温度&#xff0c;单位是摄氏度。 sudo smartctl -l scttempsts /dev/sda

自然语言处理中的文本聚类:揭示模式和见解

一、介绍 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;文本聚类是一种基本且通用的技术&#xff0c;在信息检索、推荐系统、内容组织和情感分析等各种应用中发挥着关键作用。文本聚类是将相似文档或文本片段分组为簇或类别的过程。这项技术使我们能够发现隐藏的…

AutoCompleteTextView自动完成文本框

1.AutoCompleteTextView的常用XML属性&#xff1a; andraid:completionHint 用于为弹出的下拉菜单指定提示标题&#xff0c;值为String&#xff1b;可不加。 android:completionThreshold(门槛) 用于指定用户至少输入几个字体才会显示提示&#xff0c;值为int。andraid:dro…

Doc as Code (4):使用Git做版本管理,而不是使用目录做版本管理

▲ 搜索“大龙谈智能内容”关注GongZongHao▲ 在引入版本管理工具之前&#xff0c;文档工程师使用文件系统提供的功能来管理文件。大家是这样工作的&#xff1a; 文件按照分类放在不同的目录里&#xff0c;使用编辑器&#xff08;如&#xff1a;MS Word&#xff09;打开文档进…

SOLIDWORKS --流体仿真篇

SIMULIA流体仿真是什么? 模拟并预测复杂环境下围绕和穿过实体和结构的稳态及瞬态的内外部流(包括热传递)&#xff0c;例如湍流气流、颗粒运动、表面沉积等 .提供定性、定量以及可视化的分析手段,可实现多尺度多物理的视觉效果 SIMULIA流体仿真能做什么? 1.高效的仿真前处理…

多变量线性回归练习

读取数据特征归一化 mean是均值 将特征大小控制在 -1~1之间 房屋的面积对价格的影响 卧室数量对价格的影响 损失函数 def costFunction(X,y,theta): inner np.power(Xtheta-y,2) return np.sum(inner)/(2*len(X)) 梯度下降 def gradientDescent(X,y,theta,alpha,iters…

“第六十四天” 字扩展和位扩展,外部存储器

存储器和CPU的连接; 现在的计算机MAR&#xff0c;MDR通常集成在CPU内部。存储芯片内只需一个普通的寄存器&#xff08;暂存输入&#xff0c;输出数据&#xff09;。 位扩展&#xff0c;字扩展&#xff0c;字位同时扩展&#xff1b; 位扩展&#xff1a; 位扩展的增加的是主存的…

走势分析:鹰言齐发避险需求减弱、金价仍有走低预期和空间

上交易日周二(11月07日)&#xff1a;国际现货黄金/伦敦金触底回升收跌&#xff0c;虽未收至中轨线下方&#xff0c;令后市仍有偏向震荡或再度走强的预期&#xff0c;但主图短期均线死叉信号保持&#xff0c;并对其产生压力&#xff0c;附图指标也维持空头信号发展&#xff0c;也…

深度学习入门-基于Python的理论与实现摘要记录

基本是《深度学习入门-基于Python的理论与实现》的复制粘贴&#xff0c;以作为日后的检索和查询使用 感知机 感知机接收多个输入信号&#xff0c;输出一个信号。 感知机原理 感知机接收多个输入信号&#xff0c;输出一个信号。 图2-1是一个接收两个输入信号的感知机的例子。…

【软考的故事】软考从泄题风波到机考改革,是何原委?

写在前面 有些日子没写文章了&#xff0c;今天咱不谈技术&#xff0c;就聊聊软考机考改革的事情吧&#xff0c;其实事情的起因还得从上半年的考试泄题舞弊案说起&#xff0c;也是我第一次参加软考&#xff0c;因为我是从事web开发的&#xff0c;所以对网络也是半知半解的&…