八大算法排序@希尔排序(C语言版本)

news2024/11/18 22:51:06

目录

  • 希尔排序
    • 概念
    • 算法思想
      • 示例
      • 分析
      • 结论
      • 算法步骤
        • 选择增量序列
        • 按增量分组
        • 逐步缩小增量
      • 算法优势
    • 代码实现
      • 核心算法
      • 希尔排序代码实现:
    • 时间复杂度
    • 空间复杂度
    • 特性总结



该排序会关联到直接插入排序的知识点,如果对于直接插入排序还有所疑惑,可以跳转文章过去观摩一二,希望能够帮助到你。

希尔排序

概念

  希尔排序(Shell Sort)是一种基于直接插入排序的排序算法,又称缩小增量法。其主要思想是通过对数据集合进行多次的直接插入排序,每次使用不同的增量进行直接插入排序,最终使数据基本有序,最后进行一次直接插入排序,达成排序的效果。




算法思想

希尔排序是对直接插入排序的优化算法

示例

让我们回忆一下直接插入排序的特点,下面有两个数组,
数组arr1:
数组1

数组arr2:
数组2

现在使用直接插入排序,分别对数组 arr1 和 arr2 进行升序的排序,达到以下的效果:
排序结果


分析

  对于数组arr1而言,插入的第一个元素,是数组中最大的元素9。那么对于后续要插入的元素,都要进行的一个步骤是与元素9进行交换。根据最终完成的排序结果,元素9是要排到最后的,即元素9要移动八次才能到达最终的位置。
  对于数组arr2而言,插入的第一个元素是3,根据排序完成的最终结果,我们发现只需要对元素3移动两次,就能到达最终的位置。到了最终的位置后,该元素便扎根不移动了。


结论

根据两个数组中的第一个元素插入,在整个排序中的情况。我们能够发现:
  要实现升序的排序时,对于直接插入排序而言,“ 数组中较大的元素如果较靠前 ” 的情况,比起 “ 数组中较小的元素较靠前 ” 的情况移动的次数更多,即复杂度更高。这也吻合直接插入排序的特点,如果原数组大体的趋势上越接近我们要实现的排序的效果,那么直接插入排序的效率/时间复杂度相对较低( 极端情况下,数组已经有序,那么时间复杂度为O(N) );如果原数组大体的趋势上与我们要实现的排序的效果相背而驰,那么直接插入排序的效率/时间复杂度相对更高( 极端情况下,数组是逆序,那么时间复杂度为O(N^2) )。因此直接插入排序的时间复杂度为O(N^2)。


了解至此,让我们再次解读 “ 希尔排序是对直接插入排序的优化算法 ” 这句话的意思。希尔排序,就是进行多次的直接插入排序,每次使用不同的增量,达到让数组大体上逐渐的趋近有序且是要实现的排序的效果。最后一次使用直接插入排序的算法时,此时因为数组大体上已经趋近于最终的排序效果,所以对于整个数组的元素的移动并不多,因此效率上更高。整体上相对于直接插入排序的效率而言,得到了提高。


算法步骤

  在阐述算法步骤前,让我们想这么一个问题:希尔排序是一种多次排序的算法,且每一次的排序都是直接插入排序。那么每一次排序的区别是什么?
带着这个问题,我们对上述的数组arr1进行图文模拟希尔排序的过程。


第一次直接插入排序,选择间距 (下标 ) 等于5的两两元素进行排序。如下图:
在这里插入图片描述
元素9和元素1,下标间距为5,而距离元素1间距为5的已经超出数据的范围。其他的元素同理,即数组中每个元素有且只有一个与自己距离为5的元素(除了元素5之外)。因此间距为5时,具体的直接插入排序,实现的是:
元素9和元素1的升序排序,元素9和元素1位置互换、
元素6和元素8的升序排序,元素6和元素8位置不变、
元素7和元素2的升序排序,元素7和元素2位置互选、
元素3和元素4的升序排序,元素3和元素4位置不变、
元素5单独一个,则不移动,在原位置上。

也可以这么理解:元素之间间距相等(等于5)且是“ 邻居 ”关系的,划分为一个数组。在原先各自的位置上,对数组的元素进行排序。实现在这些位置上的数组元素是升序/降序的效果。


第二次直接插入排序,选择间距 (下标 ) 等于4的两两元素进行排序。如下图:

在这里插入图片描述

元素1、5 和元素5、4,两两元素之间间距为4,元素1、5、4组成一个小数组,元素5是元素1的“邻居”,元素4是元素5的 “邻居”,对这个小数组进行升序/降序的排序。如升序排序时,原先的顺序1、5、4,将变为1、4、5。但是位置依旧是原先的那三个位置,只是在这三个位置上的元素达成了升序的排布效果。
而元素6间距为4的只有元素9的位置符合,而距离元素9间距为4的已经超出数组的范围。因此对于元素6切分的小数组中,只有元素6和元素9这两个数据,其他同理。分别对各个切分出来的小数组进行排序,最终达到整体上趋近于想要的排序效果,如升序时,大的元素靠后。
注意:实际排序时,要想想直接插入排序是如何实现的。

同样的思路,我们对间距分别为3、2、1的进行演变模拟:


第三次直接插入排序,选择间距 (下标 ) 等于3的两两元素进行排序。如下图:

在这里插入图片描述



第四次直接插入排序,选择间距 (下标 ) 等于2的两两元素进行排序。如下图:

在这里插入图片描述



最后一次直接插入排序,选择间距 (下标 ) 等于1的两两元素进行排序。如下图:
在这里插入图片描述


  以上,通过不同的间距,进行总共5次的直接插入排序,最终达成了数组arr1升序的排序效果,整个过程的实现便是希尔排序的算法逻辑了。其中所谓的间距就是前文提到的增量
  我们发现随着不同的增量,执行直接插入排序后,数组在整体上逐渐的形成了升序的效果(较大的数靠后,较小的数靠前)。当增量等于1的时候,排序的想法和直接插入排序的想法一致。


结合以上的学习,下面给出希尔排序的步骤总结:

选择增量序列

选择一个增量序列,这个序列的选择对排序的效率有影响。常用的增量序列有希尔建议的序列(例如,n/2、n/4、n/8…直到增量为1)。


注释:
  n为数组的个数,如上述对n=9的数组arr1模拟中。选择的增量序列为5、4、3、2、1。细心的同学在观察上述模拟过程图中可以发现,有些间距的直接插入排序,对数组的变动并不大。比如间距为4的时候,只是对元素5和元素4进行了交换,其他的并没有变动。对于这种间距的直接插入排序,效果不大,但是却是实打实造成一定效率的消耗的,我们可以排除掉。
  结论:不同的增量序列,对排序的效率是有影响的。如何选取一个高效的增量序列,这牵扯到数学问题。根据前人的计算,选择“ n/2、n/4、n/8…1 ”序列或者“ n/3、n/9、…1 ”序列时,效率最理想。
注:要确保增量为1的直接插入排序存在。



按增量分组

将待排序的元素按照增量分成若干个子序列,对每个子序列进行插入排序。这样,每个子序列都是部分有序的。


注释:
  如上述间距为2时,将数组 arr1 切分为两个子序列,分别是 { 1 , 2 , 5 , 8 ,4 } 、{ 6 , 3 , 9 , 7 }。然后分别对这两个子序列进行插入排序,最终在数组 arr1 中,达成了各个子序列所在的位置是有序的。arr1 数组整体上也趋近于有序。



逐步缩小增量

重复上述步骤,逐步减小增量,直至增量为1。当增量为1时,整个序列基本有序,再进行一次直接插入排序,排序完成。


注释:
  如上述间距从5、4、3、2逐步减小时,数组 arr1 整体上已经愈发的有序。当间距/增量减小为1时,整个数组基本是有序的状态,这是进行直接插入排序,完成最终的排序效果的同时也大大的增大了排序的效率。



算法优势

希尔排序的优势在于,它可以在开始时快速地将较小的元素移动到合适的位置,从而减小后续插入排序的工作量。这样,希尔排序相较于直接插入排序在效率上有所提高,特别是对于较大数据集合。虽然希尔排序不如一些更现代的排序算法,如快速排序或归并排序,但在某些特定场景下仍然有其优势。



  简洁而言,希尔排序就是对数组进行切分,隔开间距的排序、让数组整体上接近有序。再每次缩短间距,一次次的下来,数组整体上已经临近与有序的状态。当间距等于1时,排序的想法和直接插入排序的想法一致。
下面是代码的实现。


代码实现

核心算法

// 交换数值函数
void swap(int* x1,int* x2)
{
	int tmp=*x1;
	*x1=*x2;
	*x2=tmp;
}

// 直接插入排序
void InsertSort(int* a, int n)
{
	assert(a);

	// 最后一个 n-1(下标) 插入到 前n-2个排好序列的数 
	// i是有序序列的下标,当i=n-1,即数组最后一个数的下标时,则整个数组就是有序的序列了
	for (int i = 0; i < n - 1; i++)
	{
		// 单趟排序,设定end为已排序部分的最后一个元素下标
		int end = i;	// 有序序列的最后一个下标是i
		int tmp = a[end + 1];  // a[end+1] 是即将要插入的数据

		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;	
	}
	// 出了for循环,利用直接插入算法实现对数组的升序/降序的效果
}



希尔排序代码实现:

// 交换数值函数
void swap(int* x1,int* x2)
{
	int tmp=*x1;
	*x1=*x2;
	*x2=tmp;
}

// 希尔排序 : 时间复杂度O(N^1.3 - N^2)
void ShellSort(int* a, int n)
{

	// 1、gap>1相当于预算排序,让数组接近有序
	// 2、gap == 1就相当于直接插入排序,保证有序
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;//增量gap,+1保证了最后一次gap一定是1
		//gap == 1 最后一次就相当于直接插入排序
		// 直接插入排序
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;	// 有序数组的最后一个元素的下标
			int tmp = a[end + gap];	// 要插入的数据,与要排序的间距为gap

			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}

			a[end + gap] = tmp;
		}
	}

}

  观察以上代码,与直接插入排序的代码实现比对发现,希尔排序在直接插入排序外面多了一层循环,用来确保每次的直接插入排序的增量不同。而希尔排序循环内的直接插入排序与直接插入排序的区别就在于元素之间、边界的差异。具体的可以根据代码自己在图纸上结合上述演示的演示图带入数据过一遍。





时间复杂度

希尔排序的时间复杂度介于N^1.3 - N^2 之间,即O(N^1.3 - N^2)。具体的计算过程就不加以解释了,有兴趣的可以自行在网上了解、


空间复杂度

O(1)。


特性总结

1、 希尔排序是对直接插入排序的优化;
2.、当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的
了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的
对比;
3.、希尔排序的时间复杂度不好计算,需要进行推导,推导出来平均时间复杂度: O(N^1.3—
N^2);
4.、稳定性:不稳定。

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

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

相关文章

Android studio ViewPager2 底部圆点指示器应用设计

一、activity_main.xml布局文件&#xff1a; <androidx.viewpager2.widget.ViewPager2android:id"id/viewpager2"android:layout_width"403dp"android:layout_height"442dp"app:layout_constraintEnd_toEndOf"parent"app:layout_c…

基于YOLOv8深度学习的人脸面部表情识别系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

基于Python +Selenium的爬虫详解

今天我们来详细学习一些 selenium 的强大用法 一、selenium简介 由于requests模块是一个不完全模拟浏览器行为的模块&#xff0c;只能爬取到网页的HTML文档信息&#xff0c;无法解析和执行CSS、JavaScript代码&#xff0c;因此需要我们做人为判断&#xff1b; 1、什么是sele…

OR-3H7(车规级),对标ACPL-217等

提供隔离反馈 逻辑电路之间的接口 提供1通道和4通道 电平转换 DC和AC输入 SMPS中的调节反馈电路 消除接地环路 特征 电流传输比 &#xff1a; IF 5mA时最小 50%&#xff0c;VCE 5V&#xff0c;Ta25 C 高输入输出隔离电压。&#xff08;VISO3&#xff0c;750Vrms&…

微服务-理论(CAP,一致性协议)

CAP理论 关于CAP理论的介绍可以直接看这篇文章 CAP分别是什么&#xff1f; 一致性&#xff08;Consistency 一致性包括强一致性&#xff0c;弱一致性&#xff0c;最终一致性。 一致性其实是指数据的一致性&#xff0c;为什么数据会不一致呢&#xff1f; 如上面这张图&…

循环购模式:重塑消费返利的新趋势

在当今的消费市场中&#xff0c;返利模式已不再是新鲜事。然而&#xff0c;循环购模式以其独特的“消费即分享&#xff0c;分享即赚钱”的核心理念&#xff0c;正在迅速成为消费者和商家共同关注的新焦点。这种模式的出现&#xff0c;不仅重新定义了消费与返利的关系&#xff0…

23款奔驰GLC260L升级香氛负离子 车载香薰

奔驰原厂香氛系统激活原车自带系统&#xff0c;将香气加藏储物盒中&#xff0c;通过系统调节与出风口相结合&#xff0c;再将香味传达至整个车厢&#xff0c;达到净化车厢空气的效果&#xff0c;让整个车厢更加绿色健康&#xff0c;清新淡雅。星骏汇小许Xjh15863 产品功能&…

Shopee买家通系统批量注册虾皮买家号更轻松

Shopee买家通系统是一款高效、方便的工具&#xff0c;为用户提供了全自动批量注册虾皮买家号的便捷体验。在使用该系统进行自动注册时&#xff0c;用户可以享受到一系列智能化的操作&#xff0c;从而省去了繁琐的步骤&#xff0c;让整个注册流程更加轻松愉快。 首先&#xff0c…

暂时性死区:JavaScript 中隐藏的陷阱

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

CRM系统如何实现市场销售管理?CRM系统有哪些营销功能

CRM管理系统中的营销管理模块&#xff0c;它的锋芒常被销售管理所掩盖&#xff0c;但对于企业的业务来说同样重要。营销部门虽然不像销售人员一样直接面对客户&#xff0c;却是挖掘线索、商机的重要角色。CRM在市场营销领域的关键功能包括&#xff1a;营销漏斗、客户细分、营销…

软性演员-评论家算法 SAC

软性演员-评论家算法 SAC 软性演员-评论家算法 SAC优势原理软性选择模型结构目标函数重参数化熵正则化代码实现 软性演员-评论家算法 SAC 优势原理 DDPG 的问题在于&#xff0c;训练不稳定、收敛差、依赖超参数、不适应复杂环境。 软性演员-评论家算法 SAC&#xff0c;更稳定…

【算法挨揍日记】day46——377. 组合总和 Ⅳ\、96. 不同的二叉搜索树

377. 组合总和 Ⅳ 377. 组合总和 Ⅳ 题目描述&#xff1a; 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 解题思路&#xff1a; 算法思路&a…

深度生成模型之图像翻译GAN ->(个人学习记录笔记)

文章目录 深度生成模型之图像翻译GAN图像翻译的应用1. 风格迁移2. 数据增强3. 经典图像任务4. 内容创作5. 人脸图像编辑6. 人体图像编辑 图像翻译模型1. 有监督图像翻译模型2. 无监督图像翻译模型3. 多域图像翻译模型 深度生成模型之图像翻译GAN 图像翻译的应用 1. 风格迁移 …

基于python的leetcode算法介绍之动态规划

文章目录 零 算法介绍一 例题介绍 使用最小花费爬楼梯问题分析 Leetcode例题与思路[118. 杨辉三角](https://leetcode.cn/problems/pascals-triangle/)解题思路题解 [53. 最大子数组和](https://leetcode.cn/problems/maximum-subarray/)解题思路题解 [96. 不同的二叉搜索树](h…

网络安全B模块(笔记详解)- 数字取证

数据分析数字取证-attack 1.使用Wireshark查看并分析Windows 7桌面下的attack.pcapng数据包文件,通过分析数据包attack.pcapng找出恶意用户的IP地址,并将恶意用户的IP地址作为Flag(形式:[IP地址])提交; 解析:http.request.method==POST ​ Flag:[172.16.1.102] 2.继续…

属龙人的性格命运怎么样呢?

​ 属龙人慷慨大方&#xff0c;为人友爱&#xff0c;人缘很好&#xff0c;才情十足&#xff0c;细腻的思维和独到的见解常常能打动别人的心弦&#xff0c;在社交场合游刃有余&#xff0c;且魅力独特&#xff0c;身边不乏追求者。属龙人感情细腻&#xff0c;浪漫多情&#xff0…

通过软盘拷贝文件 - 华为OD统一考试

OD统一考试(B卷) 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 有一名科学家想要从一台古董电脑中拷贝文件到自己的电脑中加以研究但此电脑除了有一个3.5寸软盘驱动器以外&#xff0c;没有任何手段可以将文件持贝出来&#xff0c;而且只有一张软盘可以…

开源CalDAV和CardDav网页客户端InfCloud

本文应网友 畅天 的要求折腾。他遇到了跨域问题&#xff0c;所以老苏找了个二合一的镜像来规避。其中使用的 Baikal 和 InfCloud 都是最新的版本&#xff1b; 什么是 Baikal &#xff1f; Baikal 是一个免费的开源自托管 CalDAV 和 CardDAV 服务器&#xff0c;适用于想要管理其…

普中STM32-PZ6806L开发板(HAL库函数实现-TIM5 设置 PWM input, 获取频率跟占空比)

简介 初始化 TIM5 为 PWM input CH1&#xff0c; 获取输入PWM的频率和占空比电路原理图 连线 将 PC7 与 PA0使用跳线进行连接 其他知识 APIs /* Blocking mode: Polling */ HAL_StatusTypeDef HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel); // 堵塞捕获开…

微信好友添加频繁的原因

01 微信好友添加频繁的原因 1. 添加好友的频率太高&#xff1a;短时间内添加多个好友&#xff0c;系统会认为账号被盗&#xff0c;从而限制用户添加好友&#xff1b; 2. 频繁的发送好友请求&#xff1a;在短时间内连续发送好友请求&#xff0c;也会导致微信限制操作&#xff0…