当前位置: 首页 > news >正文

数据结构之插入排序

目录

前言

插入排序

直接插入排序

插入排序的时间复杂度

希尔排序 


前言

在日常生活中,我们不经意间会遇到很多排序的场景,比如在某宝,某东上买东西,我们可以自己自定义价格是由高到低还是由低到高,再比如在王者某耀中的每个英雄的荣耀战力,都是由高到低进行排序的,这些场景都用到了排序,但是这些场景的底层都是用一个个排序算法来实现的,本期开始,我们就要学习数据结构中很重要的一个知识点-------排序。

 几种常见的排序:

注:我们今后所有的排序都默认排升序。

本期我们主要讲解插入排序。

插入排序

直接插入排序

直接插入排序在现实生活中最常见的应用其实就是斗地主时,我们一般会将牌拍好序,然后根据自己的打法打牌,大家先仔细想想,再给牌整理时我们是怎样整理的呢?当我们摸到第一张牌时,此时它已经有序,我们摸第二张牌时,就会与第一张牌做比较,然后发生交换使之成为我们想要的顺序,当我们摸第三张牌时,我们又会与最后一张牌与倒数第二张牌进行比较,交换之后使牌的顺序成为我们想要的顺序,之后每摸一张牌,就按照此方法进行整理,最后就会得到一个有序的牌列。这就直接插入排序的一个比较常见的应用场景。在数据结构中,我们怎样实现直接插入排序呢?

要实现直接插入排序,我们可以先将直接插入排序分解为单趟排序,然后再让每趟排序组合成为整个排序。

单趟排序:

单趟排序的情景:我们要将一个元素插入一个有序数组之中。可以类比,我们摸了一张牌还没有插入手中的牌中,但是手中的牌肯定已经是一个有序的牌序列了。

单趟排序的算法思想:我们令有序的数组的最后一个元素的位置为end,要插入的元素为x。要将x插入一个有序数组,就得先让x与end位置上的元素进行比较,因为我们是排升序,所以如果x比a[end]小,就要把a[end]向后挪动一个位置,然后将end--,然后在让x与此时end位置上的元素a[end]进行比较,比较的原理同上,直到将x插入到合理的位置,那么怎样判断这样的一趟排序已经结束了呢?其实就是x比当前end位置上的元素要大,这是一个结束条件,还有就是x比有序数组所有的元素都要小,即就是要将x放在数组的第一个元素的位置上,此时end已经到了数组第一个元素位置的前一个位置之前,我们称此时end==-1,所以综上,一趟排序的结束标志就是x>a[end]或者end<0

单趟排序代码实现:

int end = size - 1;int x;while (end >= 0){if (a[end] > x){a[end + 1] = a[end];end--;}else {break;}}a[end + 1] = x;

 到了这里,我们单趟排序已经搞定了,但是上面我们已经说了,我们把整个插入排序分为了每趟排序,那么怎样将每趟排序合并成为直接插入排序呢?

每趟排序的关键点在于是把一个元素插入一个有序数组之中,其实对于一个数组而言,无论它是否是有序还是无序的,其第一个元素毋庸置疑肯定是有序的,这便是关键,我们可以从第一个与元素开始,把第一个元素当成一个有序数组,此时第二个元素就是要插入有序数组中的元素,那么此时第二哥元素插入由第一个元素组成的有序数组中就可以看成是一趟排序,这趟排序之后,第一个元素和第二个元素就组成了一个有序数组,第三个元素插入由第一个和第二个元素组成的有序数组就可以看成第二趟排序,由此依次进行多趟排序,那么整个数组的多趟排序就最终组成了直接插入排序。

直接插入排序完整代码:

void InsertSort(int* a, int size)
{assert(a);for(int end=0;end<size-1;end++){ int x = a[end + 1];while (end >= 0){if (a[end] > x){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = x;}
}
int main()
{int arr[] = { 10,9,8,7,6,5,4,3,2,1 };InsertSort(arr, sizeof(arr) / sizeof(int));for (int i = 0; i < sizeof(arr) / sizeof(int); i++){printf("%d ", arr[i]);}return 0;}

运行截图如下:

注意:

排序这里比较重要的就是边界的控制,对于直接插入排序而言,若数组的大小为sizeend的初始值就是0end的最终值就是size-2x的初始位置就是1x的最终位置就是size-1。

以上便是直接插入排序的整个过程。

插入排序的时间复杂度

最好:O(N),已经有序的数组,要插入的元素比end位置上的元素大,只用跟end位置上的元素比较一下。

最坏:O(N^2),逆序,要插入的元素比有序数组的所有元素都要小,跟end位置和end位置之前的所有元素都要比较一下。

稳定性:稳定。

希尔排序 

希尔排序其实就是插入排序的进阶版,我们知道,一个数组越有序,直接插入排序的时间复杂度越低,希尔排序其实就是为了将一个无序的数组变得有序,使插入排序变得更加简单。

希尔排序如图:

希尔排序的思想:先设置一个gap值,先把整个数组的元素分成gap组,即下标差gap的为一组,然后对每一组按照直接插入排序的思想进行排序,每一组的排序将完成一次预排序,每完成一次预排序,数组会变得比之前更加有序。我们再改变gap的值多次进行预排序,当gap==1时,就是直接插入排序,此时因为经历了多次预排序,整个数组已经变得有序,所以此时再用直接插入排序对整个数组完成最终的排序。

希尔排序的整体代码:

void ShellSort(int* a, int size)
{int gap = size;while (gap > 1){gap /= 2;//进行一趟预排序for (int i = 0; i < gap; i++){//进行每组排序for (int end = i; end < size - gap; end += gap){int x = a[end + gap];//进行单趟排序while (end >= 0){if (a[end] > x){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = x;}}}
}
int main()
{int arr[] = { 10,9,2,8,6,5,4,3,11,1 };ShellSort(arr, sizeof(arr) / sizeof(int));for (int i = 0; i < sizeof(arr) / sizeof(int); i++){printf("%d ", arr[i]);}return 0;
}

 运行截图如下:

当然,上述的方法是把三组的排序是分开的,每组自己排自己的,但是下面这种方法就是三种排序我们再一次排序中就全部排序完成,更为简洁,但是没有第一种好理解,可以理解为是第一种方法的进阶版本,但是这种进阶版本是我们经常使用的。

进阶版本代码如下:

void ShellSort(int* a, int size)
{int gap = size;while (gap > 1){gap /= 2;//进行一趟预排序,将多组排序在一次排序中就完成了,而不是按组进行排序for (int end = 0; end < size - gap; end++){int x = a[end + gap];//进行单趟排序while (end >= 0){if (a[end] > x){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = x;}}
}
int main()
{int arr[] = { 10,19,2,8,6,0,4,3,11,1 };ShellSort(arr, sizeof(arr) / sizeof(int));for (int i = 0; i < sizeof(arr) / sizeof(int); i++){printf("%d ", arr[i]);}return 0;
}

以上便是希尔排序的整个过程。

希尔排序的时间复杂度

 希尔排序的时间复杂度为:

1.最好:O(N),当整个数组为有序数组时,复杂度最小。排序算法的时间复杂度的天花板就是O(N)

 2.最坏:总共分成了gap组,每组大概就是size/gap个元素,如果每组都逆序,那么每组的复杂度又是一个1+2+...+size/gap的等差数列,平均是O(N^1.3)。

稳定性:不稳定。

插入排序的内容就是这些,我们需要注意的仍然是算法中边界的控制,在编写代码时,我们可以自己画图去控制边界,这是一个很好的方法。

好了,本期的内容到此结束^_^ 

相关文章:

数据结构之插入排序

目录 前言 插入排序 直接插入排序 插入排序的时间复杂度 希尔排序 前言 在日常生活中&#xff0c;我们不经意间会遇到很多排序的场景&#xff0c;比如在某宝&#xff0c;某东上买东西&#xff0c;我们可以自己自定义价格是由高到低还是由低到高&#xff0c;再比如在王者某…...

2023年江西省“振兴杯”网络信息行业(信息安全测试员)职业技能竞赛 Write UP

文章目录 一、2023csy-web1二、2023csy-web2三、2023csy-web3四、2023csy-web4五、2023csy-misc1六、2023csy-misc2七、2023csy-crypto1八、2023csy-re1 一、2023csy-web1 该题提供一个web靶场&#xff0c;《伟大的挑战者》&#xff0c;分值&#xff1a;5分 web页面一直在播放c…...

【5G PHY】5G NR 如何计算资源块的数量?

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…...

解决oracle.sql.TIMESTAMP序列化转换失败问题 及 J2EE13Compliant原理

目录 报错现象报错内容处理方法Oracle驱动源码总结 报错现象 oracle表中存在TIMESTAMP类型的列时&#xff0c;jdbc查出来做序列化时报错 报错内容 org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframewo…...

QQ2023备份

需要修改的路径&#xff08;共3处&#xff09; 这三处路径中&#xff0c;只有一处是需要修改的 QQPC端-主菜单-设置-基本设置-文件管理 点击上面的“”自定义“”&#xff0c;然后修改路径即可 修改路径后提示 然后等一会才会关干净QQ的相关进程&#xff0c;关闭后才会有自动…...

HNU计算机结构体系-实验2:CPU动态指令调度Tomasulo

文章目录 实验2 CPU动态指令调度Tomasulo一、实验目的二、实验说明三、实验内容问题1&#xff1a;问题2&#xff1a;问题3&#xff1a;问题4&#xff1a;问题5&#xff1a; 四、思考题问题1&#xff1a;问题2&#xff1a; 五、实验总结 实验2 CPU动态指令调度Tomasulo 一、实验…...

智慧城市是什么?为什么要建智慧城市?

智慧城市是一个通过现代科技手段推动城市管理和服务创新的概念。 具体来说&#xff0c;它利用信息技术和创新概念&#xff0c;将城市的各个系统和服务集成起来&#xff0c;以提升城市运行效率、优化城市管理和服务&#xff0c;改善市民的生活质量。 为什么要建智慧城市呢&…...

数据结构线性表-栈和队列的实现

1. 栈(Stack) 1.1 概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈 顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 …...

IntelliJ IDEA 的 HTTP 客户端的高级用法

本心、输入输出、结果 文章目录 IntelliJ IDEA 的 HTTP 客户端的高级用法前言HTTP 请求对 gRPC 请求的支持对 GraphQL 和 WebSocket 请求的支持环境文件OpenAPI 补全用于持续集成的 HTTP 客户端 CLI花有重开日,人无再少年实践是检验真理的唯一标准IntelliJ IDEA 的 HTTP 客户端…...

代码随想录算法训练营第四十六天 _ 动态规划_198.打家劫舍、213.打家劫舍II、337.打家劫舍 III。

学习目标&#xff1a; 动态规划五部曲&#xff1a; ① 确定dp[i]的含义 ② 求递推公式 ③ dp数组如何初始化 ④ 确定遍历顺序 ⑤ 打印递归数组 ---- 调试 引用自代码随想录&#xff01; 60天训练营打卡计划&#xff01; 学习内容&#xff1a; 198.打家劫舍 动态规划五步曲&a…...

ffmpeg编译问题

利用ffmpeg实现一个播放器&#xff0c;ffmpeg提供动态库&#xff0c;但是编译链接的时候遇到下面的问题&#xff1a; ../ffmpegWidgetPlayer/videoplayerwidget.cpp:23: error: undefined reference to sws_freeContext(SwsContext*) ../ffmpegWidgetPlayer/videoplayerwidget.…...

【flink番外篇】1、flink的23种常用算子介绍及详细示例(3)-window、distinct、join等

Flink 系列文章 一、Flink 专栏 Flink 专栏系统介绍某一知识点&#xff0c;并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分&#xff0c;比如术语、架构、编程模型、编程指南、基本的…...

centos7做gitlab数据灾备项目地址指向问题

如果你在 CentOS 7 上使用 GitLab 时&#xff0c;它回复的数据指向了另一个服务器的地址&#xff0c;可能是因为配置文件中的一些设置不正确。 要解决这个问题&#xff0c;可以尝试以下几个步骤&#xff1a; 检查 GitLab 配置文件&#xff1a;打开 GitLab 的配置文件&#xf…...

leetcode:93. 复原 IP 地址

复原 IP 地址 中等 1.4K 相关企业 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 ‘.’ 分隔。 例如&#xff1a;“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址&#xff0c;但…...

玄子Share-CSS3 弹性布局知识手册

玄子Share-CSS3 弹性布局知识手册 Flexbox Layout&#xff08;弹性盒布局&#xff09;是一种在 CSS 中用于设计复杂布局结构的模型。它提供了更加高效、简便的方式来对容器内的子元素进行排列、对齐和分布 主轴和交叉轴 使用弹性布局&#xff0c;最重要的一个概念就是主轴与…...

Nat easy IP ACL

0表示匹配&#xff0c;1表示任意&#xff08;主机位0.0.0.255&#xff08;255主机位&#xff09;&#xff09; rule deny source 192.168.2.1 0 设置拒绝192.168.2.1的主机通过 记住将其应用到接口上 [AR2]acl 2000 //创建基本ACL [AR2-acl-basic-2000]rule deny source 192…...

Numpy数组的数据类型汇总 (第4讲)

Numpy数组的数据类型 (第4讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…...

通讯app:

为了开发一个即时通讯的app&#xff0c;包含发送文字、语音、视频以及视频通话的功能&#xff0c;我们需要考虑以下的技术栈和实现步骤&#xff1a; 技术栈建议&#xff1a; 前端&#xff1a;React Native 或 Flutter 用于跨平台移动应用开发。后端&#xff1a;ThinkPHP Wor…...

【Backbone】TransNeXt:最新ViT模型(原理+常用神经网络汇总)

文章目录 一、近几年神经网络 Backbone 回顾1.Densenet 与 Resnet2.CBP3.SENet4.GCNet5.DANet6.PANet 与 FPN7.ASPP8.SPP-net9.PSP-net10.ECA-Net 二、TransNeXt&#xff08;2023&#xff09;1.提出问题2.Aggregated Pixel-focused Attention2.1 Pixel-focused Attention&#…...

使用Java将图片添加到Excel的几种方式

1、超链接 使用POI&#xff0c;依赖如下 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency>Java代码如下,运行该程序它会在桌面创建ImageLinks.xlsx文件。 …...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...