数据结构-插入排序+希尔排序+选择排序

目录

1.插入排序

插入排序的时间复杂度:

2.希尔排序

希尔排序的时间复杂度: 

3.选择排序

选择排序的时间复杂度:


所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序在生活中的作用很大,例如:某宝中的价格排行榜、销量排行榜,国内外的财富排行榜、院校排行榜等等,都是使用排序完成的。

下面我们看看常见的排序都有哪些:

1.插入排序

基本思想:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
实际中我们玩扑克牌时,就用了插入排序的思想:

插入排序的过程如下:

假设我们有如下一个数组:

具体实现代码如下:

while (end >= 0)
{//挪数据if (tmp < a[end]){a[end + 1] = a[end];end--;}else{break;}
}
//交换数据
a[end + 1] = tmp;

tmp中存放的是3,3小于10,10往后挪一位,3小于5,5往后挪一位......当end到2时,tmp小于2,退出循环,此时5 7 10都已经往后挪了一位,数组中的元素应该是:2 5 5 7 10,我们把tmp中存放的3和2后面的5交换即可。

以上只是一个数据的插入排序,要实现整个数组的排序,我们需要对数组的每个数据都往前插入排序一下

void InsertSort(int* a, int n)
{for (int i = 1; i < n; i++){int end = i - 1;int tmp = a[i];while (end >= 0){if (tmp < a[end]){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = tmp;}
}

插入排序的时间复杂度:

假设我们要排升序,当要排的数据刚好是降序时,时间复杂度最大,为O(N^2),因为此时排序的次数是等差数列。

当要排的数据刚好是升序的时候,是最好的情况,时间复杂度最小,但是我们在排之前并不知道数据是升序,所以至少要排N次,时间复杂度为O(N)

总结一下:

时间复杂度(最好):O(N^2)

时间复杂度(最坏):O(N)

而我们之前学过的冒泡排序,时间复杂度是O(N^2),所以插入排序优于冒泡排序。

2.希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是先选定一个整数gap,把待排序文件中所有数据分成n/gap个组,所有距离为gap的数据分在同一组内,并对每一组内的数据进行排序,最后再进行一次gap=1的分组和排序。

希尔排序有两个过程

1. 预排序  --  使接近有序。

2. 插入排序

即先进行预排序是数据接近有序,然后使用一次插入排序,使数据有序。希尔排序实际就是对插入排序的优化。

预排序:

下面我们先来对红色组进行排序:

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

注意下标 i 不能越界,所以 i < n - gap。

以上代码只能完成对红色组的排序,下面我们来将三个组都排好序:

只需在外面再加一层循环即可。

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

这样三组数据都排好序,完成了预排序,但是上述代码有似乎还可以简化:

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 = end - gap;}else{break;}}a[end + gap] = tmp;
}

只需将i+=gap,改为i++即可,当i+=gap时,我们是将三组分开排序的,先排完红色组,再排蓝色组,最后排绿色组,而当i++时,我们是多组并排的方式,这样明显效率更高。

插入排序: 

以上就是预排序的过程,预排序完,数据变成了:1 02 3 3 4 6 5 7 9 8,还需要一次插入排序,现在我们先来思考一个问题,gap的值只能给3吗?

当然不是,gap可以任意给值,只不过,给的值不同,预排序出来的数据次序就不同。

我们可以令gap=n,gap=gap/3+1, 这样每次使用的gap都在变化,而且能确保最后一次的gap一定是1,也就确保了最后一次一定进行的是插入排序。

最终代码如下:

void ShellSort(int* a, int n)
{//gap > 1  预排序//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;}}
}

希尔排序的时间复杂度: 

希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定:

《数据结构(C语言版)》--- 严蔚敏

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

3.选择排序

基本思想:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

选择排序过程如下图所示:

上图中是把待选数据遍历一遍,每次选出最小的数据放在前面,其实我们可以对其优化一下:把待选数据遍历一遍,每次同时选出最大和最小的数据,把最小的数据放在前面,最大的数据放在后面。

代码如下:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void SelectSort(int* a, int n)
{int begin = 0;int end = n - 1;int mini = begin;int maxi = end;while (begin<end){for (int i = begin; i <= end; i++){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[begin], &a[mini]);Swap(&a[end], &a[maxi]);begin++;end--;}
}

问题来了,上述代码对吗?

运行一下就会发现:

诶?不对啊,那到底哪里出错了呢?

下面我们举个极端的例子:

经过遍历以后发现,最大数的下标maxi和begin重合了,那我们交换时就出现问题了,最小数0确实放在了前面,但是最大数的位置也变了,下面再想把最大数放在后面,此时的下标就不能再用了,所以我们在交换a[begin]a[mini]的值后,要将最大数的下标更改:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void SelectSort(int* a, int n)
{int begin = 0;int end = n - 1;while (begin < end){int mini = begin;int maxi = end;for (int i = begin; i <= end; i++){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[begin], &a[mini]);//如果发生重叠,就更改下标if (begin == maxi){maxi = mini;}Swap(&a[end], &a[maxi]);begin++;end--;}
}

选择排序的时间复杂度:

选择排序的时间复杂度很简单,就是O(N^2),它每排一个数据都要遍历后面的数据一遍,遍历次数是等差数列,前面的章节中学过,等差数列的时间复杂度是O(N^2),虽然上述的代码进行优化,将遍历次数减半为N^2/2,但是量级没变,还是O(N^2)。

今天就学习这三种排序,冒泡排序、堆排序在之前的章节中已经讲解过,下节我们继续学习快速排序和归并排序,未完待续。。。

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

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

相关文章

PHP排序sort()、asort() 和 ksort() 的区别及用法

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

Amazon EC2的出现,是时代的选择了它,还是它选择了时代

目录 Amazon EC2简介 友商云服务器对比&#xff08;Amazon VS Tencent&#xff09; 友商云服务器对比&#xff08;Amazon VS Alibaba&#xff09; Amazon 云服务器的绝对优势 Amazon EC2功能 Amazon EC2 Linux 实例入门 启动实例 连接到的实例 清除的实例 终止的实例…

【Linux】一

本文使用的是云服务器来获取Linux环境 (使用虚拟机同样可以学习使用命令), 并且介绍了常用的Linux 命令. 获取Linux环境 使用xshell连接到云服务器 1.新建会话 输入主机号(云服务器的外网ip) 2.输入用户名/密码 centos的用户名:root 密码就是在后台设置的 3.成功进入 ~描…

盛元广通开放实训室管理系统2.0

开放实训室管理系统是一种基于网络和数据库的实训室信息管理系统&#xff0c;旨在提高实训室的管理水平&#xff0c;实现实训资源的优化配置和高效利用。该系统通常包括用户管理、设备管理、课程管理、考核管理等功能模块&#xff0c;能够实现实训室的预约、设备借用、课程安排…

PDF/X、PDF/A、PDF/E:有什么区别,为什么有这么多格式?

PDF 是一种通用文件格式&#xff0c;允许用户演示和共享文档&#xff0c;无论软件、硬件或操作系统如何。多年来&#xff0c;已经创建了多种 PDF 子类型来满足各个行业的不同需求。让我们看看一些最流行的格式&#xff1a;PDF/X、PDF/A 和 PDF/E。 FastReport .net下载 PDF/X …

如何远程控制别人电脑进行技术支持?

怎么提供远程技术支持&#xff1f; “我朋友的电脑出了一些问题&#xff0c;问我是否可以远程控制他的电脑帮他解决。请问有什么办法能快速的远程控制别人的电脑进行故障排除呢&#xff1f;” 当电脑出问题时&#xff0c;多数情况下会采用电话沟通进行解决&#…

Nuxt3框架全局引用外部JS/CSS文件的相关配置方法

全局引入外部文件方法&#xff1a; 找到根目录下的nuxt.config.ts配置文件&#xff1b;然后如上图所示&#xff0c;在defineNuxtConfig配置对象下app选项节点下&#xff0c;head对象中即可配置全局需要的JS或CSS文件&#xff1b; // https://nuxt.com/docs/api/configuration/…

BetterDisplay Pro for Mac(显示器校准软件)

BetterDisplay Pro是一款由waydabber开发的Mac平台上的显示器校准软件&#xff0c;可以帮助用户调整显示器的颜色和亮度&#xff0c;以获得更加真实、清晰和舒适的视觉体验。 以下是BetterDisplay Pro的主要特点&#xff1a; - 显示器校准&#xff1a;可以根据不同的需求和环境…

计算机系统的层次结构和性能指标

目录 五层结构三个级别语言 计算机性能指标CPU性能指标系统整体的性能指标 五层结构 三个级别语言 编译程序&#xff1a;将高级语言编写的源程序全部语句一次全部翻译成机器语言程序&#xff0c;而后再执行机器语言程序&#xff08;只需翻译一次&#xff09; 解释程序&#xff…

分布式与微服务 —— 初始

前言 距今微服务的提出已经过去快十个春秋&#xff0c;网络上的博文讲微服务也是一抓一大把&#xff0c;但是荔枝仍然觉得还是有必要自己梳理一下整个知识体系。在这篇文章中&#xff0c;荔枝将会以一个初学者的角度来切入&#xff0c;从分布式系统和微服务架构引入&#xff0c…

idea项目中java类名出现带 j 小红点,如何解决?

目录 一、问题描述 二、问题解决方案 1、寻找异常问题 2、解决方案 2.1常规操作方法 2.2 快速操作方法 一、问题描述 一打开idea的java项目&#xff0c;发现所有的文件边上都有带J的大红点 虽然&#xff0c;在 git bash 中进行编译时无异常。 但是视觉上给人的感受就是…

没收到Win11 23H2正式版的推送怎么升级到23H2

没收到Win11 23H2正式版的推送怎么升级到23H2&#xff1f;用户反映自己没有收到Win11 23H2正式版的更新推送&#xff0c;又想升级为23H2版本。接下来小编给大家详细介绍不同的升级方法&#xff0c;帮助更多的用户完成Win11 23H2系统的更新&#xff0c;升级后就能体验到Win11 23…

利用API连接抖音外卖与电商平台和营销系统,实现无代码开发的集成

利用API连接抖音外卖和电商平台 抖音来客&#xff0c;作为抖音生活服务商家经营平台&#xff0c;为商家提供一站式经营服务&#xff0c;其中包括入驻、上品、经营和履约等功能。商家可以通过API调用&#xff0c;实现电商平台和抖音外卖的连接&#xff0c;从而优化运营效率。例…

spark性能调优 | 内存优化

目录 我们先了解一下有哪些内存温馨提示RDD示范(spark版本2.1.1)RDD进行优化Df和Ds进行示范 我们先了解一下有哪些内存 1.storage内存 存储数据&#xff0c;缓存 可预估2.shuffle内存 计算join groupby 不可预估spark1.6之前 静态管理的&#xff0c;spark1.6之…

Vue网页中使用PDF.js弹窗显示pdf文档所有内容

本文中使用的PDF.js组件版本为3.11.174&#xff08;最新版使用上会有所不同&#xff09;&#xff0c;引入文件如下&#xff1a; 首先页面定义一个隐藏的弹窗块&#xff08;此处用ElementUI的Dialog组件&#xff09; <el-dialog ref"dialogPDF" :title"pdffi…

5分钟带你了解什么是敏捷测试?难点显而易见!

随着敏捷开发模式的普及&#xff0c;越来越多的测试同仁也开始了敏捷测试。那么究竟什么是敏捷测试&#xff1f;敏捷测试与传统测试的主要区别是什么&#xff1f;敏捷测试的难点又是什么&#xff1f;本文会对这三个问题进行讲解。注意&#xff1a;本文只是讲解敏捷测试概念相关…

linux基本指令总结--文件和目录

前言&#xff1a; 想要学好Linux操作系统&#xff0c;理解并熟悉一些基本的指令是必要的&#xff0c;下面我将整理出关于文件和目录操作的一些基本指令和用法&#xff0c;我的linux环境部署在服务器端&#xff0c;使用xshell软件进行远程操作。 本章指令整合&#xff1a; ls查…

企业怎样申请SSL证书?

对于很多企业而言&#xff0c;使用SSL证书加密网站已经显得尤为重要&#xff0c;这不仅仅是关乎企业的网站安全&#xff0c;同时也关系着企业的形象以及用户的信赖。既然使用https协议已经众多企业认可&#xff0c;那么我们该如何给自己的网站申请以及安装SSL证书&#xff1f; …

“智能与未来”2024世亚国际智能机器人展会(简称:世亚智博会)

随着科技的不断发展&#xff0c;智能机器人已经成为了当今社会的热门话题。无论是工业生产、医疗护理、家庭服务等领域&#xff0c;智能机器人都发挥着越来越重要的作用。而世亚智博会作为智能机器人领域的专业展会之一&#xff0c;旨在为全球的智能机器人产业提供一个展示、交…

矩阵运算_矩阵的协方差矩阵/两个矩阵的协方差矩阵_求解详细步骤示例

1. 协方差矩阵定义 在统计学中&#xff0c;方差是用来度量单个随机变量的离散程度&#xff0c;而协方差则一般用来刻画两个随机变量的相似程度。 参考&#xff1a; 带你了解什么是Covariance Matrix协方差矩阵 - 知乎 2. 协方差矩阵计算过程 将输入数据A进行中心化处理得到A…