[排序算法]插入排序+希尔排序全梳理!

news2024/11/15 22:04:02

目录

  • 1.排序是什么?
    • 1.1排序的概念
    • 1.2排序运用
    • 1.3常见的排序算法
  • 2.插入排序分类
  • 3.直接插入排序
    • 基本思想
    • 具体步骤:
    • 动图演示
    • 代码实现
    • 直接插入排序的特性总结:
  • 4. 希尔排序
    • 基本思想
    • 具体步骤
    • 动图演示
    • 代码实现
    • 希尔排序的特性总结:
  • 5.总结

1.排序是什么?

1.1排序的概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i] = r[j],且 r[i] 在 r[j] 之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不断地在内外存之间移动数据的排序。

1.2排序运用

这里给大家举几个生活中,常见排序的例子:

购物平台里面按某个商品的维度排序:
在这里插入图片描述
报考志愿时全国高校的排名情况:
在这里插入图片描述

其实在我们日常生活中会经常使用排序,可见排序与我们生活息息相关。

1.3常见的排序算法

在这里插入图片描述

2.插入排序分类

插入排序可以分为:直接插入排序希尔排序
在这里插入图片描述

3.直接插入排序

基本思想

直接插入排序的思路和打扑克牌时给牌排序的思路类似:

比如比如我手中有红桃 6,7,9,10 这 4 张牌,已经处于升序排列:
在这里插入图片描述
这时候,我又抓到一张黑桃 8,如何让手中的 5 张牌重新变成升序呢?

在这里插入图片描述
很简单,其实是在已经有序的 4 张牌中找到红桃 8 应该插入的位置,也就是 7 和 9 之间,把红桃 8 插进去:

在这里插入图片描述

就像玩牌一样,插入排序算法也采用了类似的思想:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

具体步骤:

1)维护一个有序区,把元素一个个插入有序区的适当位置,直到所有元素都有序为止。
2)在待排序的元素中,假设前 n-1 个元素已有序,现将第 n 个元素插入到前面已经排好的序列中,使得前 n 个元素有序。按照此法对所有元素进行插入,直到整个序列有序。

接下来演示一下直接插入排序在数组中的具体实现步骤。

给定一组无序数组如下:

在这里插入图片描述
我们把首元素 6 作为有序区,此时有序区只有这一个元素:
在这里插入图片描述

第一轮,让元素 9 和有序区的元素依次比较,9 > 6,所以元素 9 和元素 6 无需交换。

此时有序区的元素增加到两个:

在这里插入图片描述

第二轮,让元素 7 和有序区的元素依次比较,7 < 9,所以把元素 7 和元素 9 进行交换:
在这里插入图片描述
7 > 6,所以把元素 7 和元素 6 无需交换。

此时有序区的元素增加到三个:

在这里插入图片描述

第三轮,让元素 4 和有序区的元素依次比较,4 < 9,所以把元素 4 和元素 9 进行交换:
在这里插入图片描述
4 < 7,所以把元素 4 和元素 7 进行交换:
在这里插入图片描述

4 < 6,所以把元素 4 和元素 6 进行交换:
在这里插入图片描述

此时有序区的元素增加到四个:
在这里插入图片描述

以此类推,插入排序一共会进行(数组长度-1)轮,每一轮的结果如下:
在这里插入图片描述

动图演示

我们来看一组动图演示:
在这里插入图片描述

代码实现

void InsertSort(int* a, int n) {
	//数组的长度是n,那么最后一个数据是n-1,倒数第二个数据是n-2
	for (int i = 0; i < n - 1; ++i) {
		// [0 end]有序,把end+1的位置的值插入进去,保持它依旧有序
		int end = i; //记录有序序列的最后一个元素的下标
		int tmp = a[end + 1]; //待插入的元素
		while (end >= 0) {
			if (tmp < a[end]) {
				a[end + 1] = a[end];
				--end;
			}
			else {
				break;
			}
		}
		//代码执行到此位置有两种情况:
		//1.待插入元素找到应插入位置(break跳出循环到此)。
		//2.待插入元素比当前有序序列中的所有元素都小(while循环结束后到此)。
		a[end + 1] = tmp;
	}
}

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)

最好的情况:数组是有序的或者接近有序的,那么时间复杂度就是:O(N)
最坏的情况:数组是逆序的,那么时间复杂度就是: O(N^2)
元素集合越接近有序,直接插入排序算法的时间效率越高。

  1. 空间复杂度:O(1),这里没有额外开辟空间.
  2. 稳定性:稳定。 直接插入排序在遇到相同的数时,可以就放在这个数的后面,就可以保持稳定性了,所以说这个排序是稳定的。

4. 希尔排序

基本思想

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

希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进。

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

具体步骤

具体步骤是:

1)先选定一个小于 N 的整数 gap 作为第一增量,然后将所有距离为 gap 的元素分在同一组,并对每一组的元素进行直接插入排序。然后再取一个比第一增量小的整数作为第二增量,重复上述操作。
2)当增量的大小减到1时,就相当于整个序列被分到一组,进行一次直接插入排序,排序完成。

为什么要让 gap 由大到小呢?

原因是:

gap 越大,数据挪动得越快。

gap 越小,数据挪动得越慢。

前期让 gap 较大,可以让大的数据可以更快到最后,小的数可以更快到前面,减少挪动次数。

一般情况下,取序列的一半作为增量,然后依次减半,直到增量为 1

给定一组无序数组如下:

在这里插入图片描述
第一轮,我们用序列长度的一半作为第一次排序时 gap 的值,此时相隔距离为 5 的元素被分为一组(共分了 5 组,每组有 2 个元素),然后分别对每一组进行直接插入排序。

在这里插入图片描述

第二轮,gap 的值折半,此时相隔距离为 2 的元素被分为一组(共分了 2 组,每组有 5 个元素),然后再分别对每一组进行直接插入排序。
在这里插入图片描述

第三轮,gap 的值再次减半,此时 gap 减为 1,即整个序列被分为一组,进行一次直接插入排序。
在这里插入图片描述

动图演示

我们来看一组动图演示:
在这里插入图片描述

代码实现

/*希尔排序
* 时间复杂度:O(N)
* 如果gap越小,越接近有序;
* gap越大,那么大的数据可以更快到最后,小的数可以更快到前面,但它不接近有序
*/
void ShellSort(int* a, int n) {
	//1. gap>1 预排序
	//2. gap == 1 直接插入排序
	int gap = n;
	while (gap > 1) {
		gap = gap / 3 + 1;
		//进行一趟排序
		for (int i = 0; i < n - gap; ++i) {
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end]) {
					a[end + gap] = a[end];
					end -= gap;
				}
				else {
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

希尔排序的特性总结:

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

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

  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的
    希尔排序的时间复杂度都不固定:
    《数据结构(C语言版)》— 严蔚敏
    在这里插入图片描述

《数据结构-用面相对象方法与C++描述》— 殷人昆
在这里插入图片描述
因为我们的 gap 是按照 Knuth 提出的方式取值的,而且 Knuth 进行了大量的试验统计,我们暂时就按照:O(n1.25)到
O ( 1.6 ∗ n 1.25 ) 来计算。

时间复杂度:(N*logN),平均时间复杂度:O ( n 1.3)

空间复杂度:O ( 1 )

5.总结

在这里插入图片描述

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

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

相关文章

一种改进的经验小波变换方法(Python环境)

经验小波变换EWT是Gilles基于小波分析理论提出的一种新的自适应信号分解方法&#xff0c;该方法主要分为三个步骤&#xff1a;1.根据傅里叶谱的特性自适应划分频谱&#xff0c;获得一组边界&#xff1b;2.根据边界序列和Meyer小波构造滤波器组&#xff1b;3.滤波重构&#xff0…

Django——Admin站点(Python)

#前言&#xff1a; 该博客为小编Django基础知识操作博客的最后一篇&#xff0c;主要讲解了关于Admin站点的一些基本操作&#xff0c;小编会继续尽力更新一些优质文章&#xff0c;同时欢迎大家点赞和收藏&#xff0c;也欢迎大家关注等待后续文章。 一、简介&#xff1a; Djan…

Midjourney应用:电商模特换装

今天我们应用的是Midjourney应用&#xff1a;电商模特换装 网上找到一件衣服&#xff0c;没有模特 方法一&#xff1a;两图片融合&#xff0c;BLEND命令&#xff0c;效果不是很理想失真 方法二&#xff1a;服装图片垫图说明细节缺失https://cdn.discordapp.com/attachments/1…

map/set和unordered_map/unordered_set的区别及其适用情况

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…

我喜欢的vscode插件

有个更全的&#xff1a;提高编程效率的30个VScode插件 Image preview&#xff08;图片预览&#xff09; any-rule&#xff08;正则表达式大全&#xff09; px to rem & rpx & vw(cssrem)&#xff08;px和rem之间转换&#xff09; 小程序开发助手 Auto Close Tag A…

【Vulhub】Fastjson 1.2.24_rce复现

文章目录 一&#xff0c;Fastjson是什么&#xff1f;二&#xff0c;fastjson漏洞原理三&#xff0c;判断是否有fastjson反序列化四&#xff0c;复现Fastjson 1.2.24_rce(vulhub)环境配置1.判断是否存在Fastjson反序列化2.反弹shell3.启动RMI服务器4.构造恶意POST请求 一&#x…

【赠书第26期】AI绘画教程:Midjourney使用方法与技巧从入门到精通

文章目录 前言 1 Midjourney入门指南 1.1 注册与登录 1.2 界面熟悉 1.3 基础操作 2 Midjourney进阶技巧 2.1 描述词优化 2.2 参数调整 2.3 迭代生成 3 Midjourney高级应用 3.1 创意启发 3.2 团队协作 3.3 商业应用 4 总结与展望 5 推荐图书 6 粉丝福利 前言 在…

使用QT可视化操作信号与槽函数详解

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、QT信号与槽机制概述 三、实际操作步骤 四、案例演示 五、总结 一、引言 在…

防火墙技术基础篇:eNSP配置防火墙主备备份的双机热备

防火墙技术基础篇&#xff1a;配置主备备份的双机热备 防火墙双机热备&#xff08;High Availability, HA&#xff09;技术是网络安全中的一个关键组成部分&#xff0c;通过它&#xff0c;我们可以确保网络环境的高可靠性和高可用性。下面我们一起来了解防火墙双机热备的基本原…

在CentOS系统上安装Oracle JDK(华为镜像)

在CentOS系统上安装Oracle JDK(华为镜像) 先爱上自己&#xff0c;再遇见爱情&#xff0c;不庸人自扰&#xff0c;不沉溺过去&#xff0c;不为自己的敏感而患得患失&#xff0c;不为别人的过失而任性&#xff0c;这才是终身浪漫的开始。 https://repo.huaweicloud.com/java/jdk …

详解 Spark 核心编程之 RDD 算子

RDD 算子就是 RDD 的方法 一、转换算子 根据数据处理方式的不同可以分为单 Value 类型、双 Value 类型和 Key-Value 类型 1. map /**单 Value 类型算子函数签名&#xff1a;def map[U: ClassTag](f: T > U): RDD[U]功能&#xff1a;将处理的数据逐条进行映射转换&#xff0…

【CGAL】Region_Growing 检测平面并保存

目录 说明一、算法原理二、代码展示三、结果展示 说明 本篇博客主要介绍CGAL库中使用Region_Growing算法检测平面的算法原理、代码以及最后展示结果。其中&#xff0c;代码部分在CGAL官方库中提供了例子。我在其中做了一些修改&#xff0c;使其可以读取PLY类型的点云文件&…

OSPF状态机+SPF算法

OSPF状态机 1.点到点网络类型 down-->init-->(前提为可以建立邻接)exstart——>exchange-->若查看邻接的DBD 目录后发现不用进行LSA 直接进入ful。若查看后需要进行查询、应答先进入loading&#xff0c;在查询应答完后再进入 fuIl: 2.MA网络类型 down --&g…

269 基于matlab的四连杆机构动力学参数计算

基于matlab的四连杆机构动力学参数计算。将抽油机简化为4连杆机构&#xff0c;仿真出悬点的位移、速度、加速度、扭矩因数、游梁转角等参数&#xff0c;并绘出图形。程序已调通&#xff0c;可直接运行。 269机构动力学参数计算 位移、速度、加速度 - 小红书 (xiaohongshu.com)

煤炉Mecari防封攻略:如何降低封店概率?

不少卖家反馈&#xff0c;Mecari不少封店情况存在&#xff0c;今天就来整理一下常见原因及解决方法。 一、煤炉被封号的原因如下 1、IP不稳定&#xff1a;一定不要多次切换线路&#xff0c;IP跳动频繁&#xff0c;IP不纯净&#xff0c;多人共享&#xff0c;均会导致账号活动异…

linux开发之设备树六、linux下pinctrl子系统管理设置pin管脚的复用功能(一般原厂提供)

客户端的编写格式是固定的&#xff0c;不管哪家原厂的处理器&#xff0c;格式都是一样的 对于服务端部分是原厂提供&#xff0c;各个芯片肯定就不一样了&#xff0c;主要在于编写的格式不同 pinctrl客户端写法 使用pinctrl设置管脚复用 在kernel/arch/arm64/boot/dts/rockchi…

2022年全国职业院校技能大赛高职组“信息安全管理与评估”赛项第三阶段任务书

第三阶段竞赛项目试题 本文件为信息安全管理与评估项目竞赛-第三阶段试题。根据信息安全管理与评估项目技术文件要求&#xff0c;第三阶段为夺旗挑战CTF&#xff08;网络安全渗透&#xff09;。 本次比赛时间为180分钟。 介绍 夺旗挑战赛&#xff08;CTF&#xff09;的目标…

蓝桥杯第17135题 不完整的算式 C++ Java Python

目录 题目 思路和解题方法 步骤 1&#xff1a;识别缺失的部分 步骤 2&#xff1a;根据已知条件计算或推断 步骤 3&#xff1a;处理特殊情况和验证 c 代码 Java 版本 Python 版本&#xff08;仅供参考&#xff09; 代码和解题细节&#xff1a; 题目 题目链接&#xff…

科迅图书馆云平台 WebCloud.asmx SQL注入致RCE漏洞复现

0x01 产品简介 科迅图书馆云平台又称集群式图书管理系统是采用B/S架构的垂直管理模式,管理系统下设城市集群式图书馆管理系统+电子阅览室+门户网站,不仅实现了总馆对分馆的在线管理,而且实现了资源共享和建设图书馆联合服务体系,可以方便读者在图书馆门户网站或者其中任何…

CSS绘制圆弧

css绘制如图的圆弧&#xff1a; 这种矩形弧形的效果中&#xff0c;弧形的效果一般是由一条曲线拉伸出来的&#xff0c;这条曲线往往是属于一个椭圆的&#xff0c;所以可以绘制一个椭圆&#xff0c;截取部分可视区域实现效果。 <style> .wrapper{width: 400px;height: 60…