排序(1)——直接插入排序、希尔排序

 

目录

一、直接插入排序

1.简介

 2.思路与代码

3.复杂度与稳定性分析

(1)时间复杂度

(2)空间复杂度

(3)稳定性

二、希尔排序

1.简介

2.思路与代码

(1)分组排序

(2)多组并排

3.复杂度与稳定性分析

 (1)时间复杂度

(2)空间复杂度

(3)稳定性


         为了追求生产生活的便捷与秩序,我们常常需要对一系列的对象进行排序处理,排序在我们生活中无处不在。在C语言中面对众多的数据,众多优秀的程序员们发明了许多不同思想,不同方法的排序算法。我们今天所要接触到的就是其中之二:直接插入排序与希尔排序。

        注:本文以升序为例

一、直接插入排序

1.简介

        顾名思义,直接插入排序就是将数据直接插入到顺序之中。详细而言就是面对一个数组,假定某一位置之前的元素已经有序,需要将该元素也排入顺序之中,那么就需要这个元素与之前的顺序序列一一比较,找到其合适的位置插入进去。

 2.思路与代码

        在写排序算法的时候,最重要的是要明确单趟排序的思路,因为整体排序实际就是很多个单趟排序的不断重复。所以只要我们写出了单趟排序,把它丢进循环里,调整一下每一次排序的变量即可。

        对于一个数组a,它具有n个元素。对于任一元素下标end,假设[0,end]已经有序,我们所要完成的就是将下标为end+1(即有序序列后一个)的元素插入到有序序列对应的位置,使得有序范围变为[0,end+1]。对此我们需要将所需要插入的元素与有序序列从后往前一一比较,如若小于所比较的元素则证明应该插入在它的左边部分,那么就继续迭代与下一个位置比较;否则直接插入右边位置即可。

    //单趟排序	//[0,end]已经有序,将end+1插入有序数组内int endint	tmp = a[end + 1];while (end >= 0){if (tmp < a[end]){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = tmp;

        那么对于整体而言,我们只需要采用循环的方式,将end从0开始,排到end成为最后一个元素为止。初值end=0,[0,0]单个元素有序;排完end=end-2这次循环后,end自增为n-1,说明[0,n-1]有序,即所有元素已经有序,就可以停止了。

void InsertSort(int* a, int n)
{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;}}a[end + 1] = tmp;}
}

3.复杂度与稳定性分析

(1)时间复杂度

        插入排序是从一个到多个的顺序扩展,其时间复杂度的主要贡献者是插入过程中寻找位置的过程。

        最差情况就是数组逆序的情况,此时每一次插入都需要完整地遍历之前的有序序列,所以此时的时间复杂度就是标准的等差数列求和,所以是O(n^2)

        最佳情况下,就是数组顺序的情况下,此时无需任何交换,对每个元素只需比较一次就确定了位置,所以相当于遍历了一遍数组,时间复杂度是O(n)

(2)空间复杂度

        插入排序并未用到多余额外的空间,所以空间复杂度是O(1)

(3)稳定性

        插入排序是稳定的。

        借用百度百科的解释:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

        插入排序在排序过程中因为是依次取元素向前排的,只要保证在相等时end位置不向后挪动,即可确保相对位置不变,算法也就稳定了。

二、希尔排序

1.简介

        希尔排序是由DL.Shell于1959年提出,因而被命名为希尔排序。希尔排序可以看作是插入排序的升级版,它对插入排序取长补短。因为插入排序处理有序序列效率很高,而处理逆序序列效率很低,所以希尔采取预排序的方法,将数组用较低的代价排列成为接近有序的状态,再使用插入排序完成最后的排序,这样的方法使得排序的效率相较于插入排序有了巨大的飞跃。

2.思路与代码

        对于希尔排序,我们所需要重点解决的就是其预排序部分的实现,希尔排序在预排序中要求以gap为间隔进行预排序,即每隔gap个位置的元素称为一组,将这些组互不相干地分别进行插入排序。由于一次交换的发生在距离为gap的两个元素之间,因而使得较大元素更快被换到后方,而较小元素也更快换到前方。

        对于一个无序数组啊a,假定本次预排序gap为3。

        首先进行分组,将下标为0+n*3的元素视为一个组,另外两组下标为1+n*3和2+n*3,即每一组是下标加减gap的关系。我们这里说视为是因为并未为它们新开空间进行存放,只是我们人为将其主观划为三组,实际上其还是存在原数组中。这样理解比较方便,只是需要写代码的时候清楚注意到就好。

        下一步将三组分别进行插入排序,保证三组分别有序。

        最后放到原数组,这里说放回也是便于理解,同样地我们是在原数组中主观意识划分下的处理,分别排序这一步就是在原数组中进行调整,并不存在“放回”这一步。

(1)分组排序

        这种方案比较符合我们的认知逻辑,因为gap是间隔的距离,所以我们可以知道需要排序的组数也就是gap组,每组对应的首元素也就是前gap个元素,所以我们可以循环gap次来对每一组分别进行插入排序。

        直接插入排序的代码无需解释了,只是有一点改动。因为现在处理的是间隔为gap的一组数据,所以原先插入排序的调整(如end等)应该每次调整gap。

        除此之外,还需要补充的一点是gap的选取。当gap选的过小时,与直接插入排序区别不大开销会变大;如果选的过大则难以很好的实现“重沉轻浮”的目标。所以动态的gap才是好gap,gap先很大,尽快区分出数据,然后逐渐变小,进行细化。gap = gap / 3 + 1是业界普遍认定的比较好的选择,具体原因等我学会再告诉你们(略略略)。无论gap如何选取,我们都应该知道gap最后一步应该是1,这样相当于最后一步的直接插入排序,完成后才能宣告结束,所以gap的递推关系要满足使得gap递减,并且可以到达1。

void ShellSort(int* a, int n)
{//预排序//int gap = 3;int gap = n;//gap>1时是预排序//gap==1时是直接插入排序while (gap > 1){//gap在循环中应该递减为1//gap = gap / 2;  //gap/2最后都可以到达1gap = gap / 3 + 1; //对gap除以3,商可能是任意整数并且一定比被除数小,即gap是递减的//对于gap/3循环,gap是有可能不经过1而直接到达0的,所以需要加1确保gap一定可以到达1for (int j = 0; j < gap; j++){for (int i = j; i < n - gap; i += gap)//i作为坐标预处理数组元素下标{int end = i;//前end个元素已经有序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;}}}
}

(2)多组并排

        多组并排和分组排序采取的思路一致,只是代码写法上有所不同。分组排序代码呈现与我们理解希尔排序的方式相同,而多组并排的代码呈现则是将其中两层循环合并起来了。因为原来代码每个组分别遍历自己的组员,每个组员的处理方式也都是一样的,这实际上就是遍历了整个原数组,所以多组并排就是遍历一遍原数组,遍历到不同的组员采取一样的处理方式。

void ShellSort2(int* a, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++){int end = i;int cmp = a[i + gap];while (end >= 0){if (cmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}a[end + gap] = cmp;}}}
}

3.复杂度与稳定性分析

 (1)时间复杂度

        希尔排序的时间复杂度很明显不是我能算出来的(哭丧脸)。

        希尔排序最佳情况是数组顺序,时间复杂度为O(n)

        通过万能的网友大佬们,我得知希尔排序的一般情况下时间复杂度O(n^{1.3}) ~ O(n^{1.5})之间,还是很厉害的。

(2)空间复杂度

        希尔排序没有多用额外空间,空间复杂度为O(1)

(3)稳定性

        希尔排序是不稳定的。

        直接插入排序一样比较挪动只发生在相邻位置,可以控制使其稳定。但希尔排序存在大量的组内的大跨度交换,很容易调换相对顺序,所以是不稳定的。

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

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

相关文章

系统架构设计师教程(十七)通信系统架构设计理论与实践

通信系统架构设计理论与实践 17.1 通信系统概述17.2 通信系统网络架构17.2.1局域网网络架构17.2.2 广域网网络架构17.2.3 移动通信网网络架构17.2.4存储网络架构17.2.5 软件定义网络架构17.3 网络构建关键技术17.3.1 网络高可用设计17.3.2 IPv4与IPv6融合组网技术17.3.3 SDN技术…

09. Springboot集成sse服务端推流

目录 1、前言 2、什么是SSE 2.1、技术原理 2.2、SSE和WebSocket 2.2.1、SSE (Server-Sent Events) 2.2.2、WebSocket 2.2.3、选择 SSE 还是 WebSocket&#xff1f; 3、Springboot快速集成 3.1、添加依赖 3.2、创建SSE控制器 3.2.1、SSEmitter创建实例 3.2.2、SSEmi…

macOS跨进程通信: Unix Domain Socket 创建实例

macOS跨进程通信: Unix Domain Socket 创建实例 一&#xff1a; 简介 Socket 是 网络传输的抽象概念。 一般我们常用的有Tcp Socket和 UDP Scoket&#xff0c; 和类Unix 系统&#xff08;包括Mac&#xff09;独有的 Unix Domain Socket&#xff08;UDX&#xff09;。 Tcp So…

Scratch:启蒙少儿编程的图形化魔法

在当今这个数字化时代&#xff0c;编程已经成为了一项重要的基础技能。就像学习阅读和写作一样&#xff0c;掌握编程能够打开通往未来世界的大门。对于孩子们来说&#xff0c;Scratch作为一种图形化编程语言&#xff0c;不仅简单有趣&#xff0c;而且非常适合作为编程学习的入门…

科技助力“双碳”:墨水屏电子桌牌在绿色办公中的作用

随着科技的发展&#xff0c;人们对绿色环境可持续发展也越来越重视&#xff0c;所以&#xff0c;我国在几年前&#xff0c;就提出了“双碳”政策&#xff08;即碳达峰与碳中和的简称。2020年9月中国明确提出2030年“碳达峰”与2060年“碳中和”目标&#xff09;&#xff0c;而作…

单调栈第二天(还没写完)

503.下一个更大元素II 力扣题目链接(opens new window) 给定一个循环数组&#xff08;最后一个元素的下一个元素是数组的第一个元素&#xff09;&#xff0c;输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更…

卸载软件Geek Uninstaller,MySQl安装不成功

最近刷最右的时候&#xff0c;看到两个帖子都是MySQl安装过程总是出现问题。大概两年前我也遇到了这个问题&#xff0c;推荐一款软件。 是因为在安装的过程之中&#xff0c;出现了问题。然后你再进行安装的时候&#xff0c;没有完全将原来安装的软件卸载掉&#xff0c;导致有注…

垃圾填埋气体监测与告警一体化环保监测5G云网关

数字化时代数据采集和传输我认为变得非常重要。为了满足这一需求&#xff0c;我们推出了一款具备多种功能的数据采集器。这款产品不仅集成了8DI干湿节点、4DO继电器、6AI电流/电压型传感器&#xff0c;还支持与多个云平台进行上行对接。通过这些功能&#xff0c;用户可以轻松实…

深入浅出理解目标检测的非极大值抑制(NMS)

一、参考资料 物体检测中常用的几个概念迁移学习、IOU、NMS理解 目标定位和检测系列&#xff08;3&#xff09;&#xff1a;交并比&#xff08;IOU&#xff09;和非极大值抑制&#xff08;NMS&#xff09;的python实现 Pytorch&#xff1a;目标检测网络-非极大值抑制(NMS) …

机器学习整理

绪论 什么是机器学习&#xff1f; 机器学习研究能够从经验中自动提升自身性能的计算机算法。 机器学习经历了哪几个阶段&#xff1f; 推理期&#xff1a;赋予机器逻辑推理能力 知识期&#xff1a;使机器拥有知识 学习期&#xff1a;让机器自己学习 什么是有监督学习和无监…

CubeMX生成工程文件夹解释

使用CubeMXKeil的工程&#xff0c;物理文件夹结构如下&#xff1a; 文件夹、文件&#xff0c;众多&#xff0c;但我们平时使用到的&#xff0c;主要是两个入口文件&#xff0c;即以下的&#xff1a;1和2. 1、***.uvprojx 位置&#xff1a;工程目录\MDK-ART文件夹下。 Keil的工…

【C++】STL和vector容器

STL和vector容器 基本概念六大组件容器算法迭代器容器算法迭代器 vector容器基本概念vector构造函数赋值vector的容量和大小vector插入与删除vector存取数据函数原型 vector互换容器vector预留空间vector容器嵌套容器 基本概念 长久以来&#xff0c;软件届一直希望建立一种可重…

基于 java+springboot+mybatis电影售票网站管理系统前台+后台设计和实现

基于 javaspringbootmybatis电影售票网站管理系统前台后台设计和实现 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承…

国内首个!亚信安全获得CCRC数据分类分级产品认证证书

亚信安全信数数据分类分级系统AISDC V1.0&#xff0c;荣获中国网络安全审查认证和市场监管大数据中心颁发的首个数据分类分级产品IT产品信息安全认证证书&#xff01;标志着亚信安全在大数据安全领域的强大技术实力以及专业研究&#xff0c;正式获得国内数据分类分级产品评定的…

通过LiveNVR实现海康大华华为宇视等监控摄像头在服务器上录像存储,并web无插件直播和回放

支持云端录像服务器上面集中录像存储在部署LiveNVR的服务器上面 1、流媒体服务软件2、配置开启录像(云端录像)3、录像回看(云端录像)3.1、查看录像3.1.1、时间轴视图3.1.2、列表视图 4、云端录像相关接口5、如何分享时间轴录像回看&#xff1f;6、iframe集成示例7、RTSP/HLS/FL…

centos 7 增加临时路由及永久路由

centos 7 增加临时路由及永久路由 如果增加临时路由&#xff0c;要先安装net-tools , sudo yum install net-tools route add -net 10.1.0.0 gw 10.1.1.1 netmask 255.255.0.0 意思是增加了一条动态路由&#xff0c;网关10.1.1.1 ,10.1.x.x 的所有ip都走这个网关 此种方式&am…

[框架系列]-[通用lock框架]集成及具体配置使用

目录 一&#xff1a;框架集成 1.添加pom依赖 2.开启lock配置 二&#xff1a;配置详细介绍 1.配置清单 2.具体配置介绍 &#xff08;1&#xff09;implementer &#xff08;2&#xff09;type &#xff08;3&#xff09;transactionStrategy &#xff08;4&#xff09…

Dev-Home:又一个开发人员控制中心神器,微软官方出品!

前两周&#xff0c;微软针对开发人员推出的windows控制中心&#xff1a;Dev-Home&#xff0c;迎来了0.9的预览版&#xff0c;这次重点的更新是支持Window 10了&#xff0c;之前一直都只支持Windows 11。 Dev-Home核心有两个功能&#xff1a;系统监控小组件和Gtihub扩展小组件。…

ISO 14229和UDS:汽车诊断的黄金标准

UDS简介&#xff1a; UDS是Unified Diagnostic Services的缩写&#xff0c;全名统一诊断服务。它是一种用于汽车电子控制单元&#xff08;ECU&#xff09;之间进行诊断和通信的标准协议&#xff0c;属于ISO 14229标准的一部分。 UDS的起源和背景&#xff1a; UDS的起源可以追…

一个处理Range List的面试题解法

大纲 题目解法Rangeaddremove ToolsRangeListaddremove 代码 最近看到一个比较有意思的面试题。题目不算难&#xff0c;但是想把效率优化做好&#xff0c;也没那么容易。 我们先看下题目 题目 // Task: Implement a class named RangeList // A pair of integers define a ra…