数据结构之插入排序

目录

前言

插入排序

直接插入排序

插入排序的时间复杂度

希尔排序 


前言

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

 几种常见的排序:

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

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

插入排序

直接插入排序

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

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

单趟排序:

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

单趟排序的算法思想:我们令有序的数组的最后一个元素的位置为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)。

稳定性:不稳定。

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

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

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

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

相关文章

云原生的 CI/CD 框架tekton - pipeline(一)

文章目录 1. 官方介绍2. 组件2.1 Tekton Pipelines2.2 部署pipeline2.3 部署dashborad2.3.1 task2.3.2 taskrun2.3.3 Pipeline2.3.4 PipelineRun 3. 案例案例1: 拉取代码并查看readmestep1: 创建task - 拉取代码step2: 创建task - 查看reamdestep3: 创建task的编排 - pipelines…

软件测试面试题解析--什么题是必问的?

设计测试用例的主要方法有哪些&#xff1f;简述一下缺陷的生命周期&#xff1f;测试流程&#xff1f;项目流程&#xff1f;验收测试中和β测试区别&#xff1f;如何维护测试用例&#xff1f;每天测多少用例怎么分配的测试的一天能找多少bug你在上一家公司&#xff0c;写没写过测…

Selenium+Unittest+HTMLTestRunner框架更改为Selenium+Pytest+Allure(二)

1 代码框架 整体项目结构如图&#xff1a; Common&#xff1a;公共库 Logs&#xff1a; 日志目录 Page&#xff1a; 页面元素 Report&#xff1a;测试报告 TestCase&#xff1a;测试用例 TestData&#xff1a; 测试数据 2 单模块运行 直接上代码&#xff1a; # -*- coding…

详细介绍如何使用 SSD 进行实时物体检测:单次 MultiBox 探测器-含源码

介绍 在实时对象检测中,主流范例传统上采用多步骤方法,包括边界框、像素或特征重采样以及高质量分类器应用的提议。虽然这种方法已经实现了高精度,但其计算需求往往阻碍了其对实时应用的适用性。然而,单次多框检测器 (SSD) 代表了基于深度学习的对象检测的突破性飞跃。SSD…

SpringCloud | Dubbo 微服务实战——注册中心详解

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 |Eureka,Nacos,Consul,Zookeeper在Spring Cloud和Dubbo中实战 引言 在项目开发过程中&#xff0c;随着项目不断扩大&#xff0c;也就是业务的不断增多&#xff0c;我们将采用集群&#xf…

647. Palindromic Substrings 516. Longest Palindromic Subsequence

647. Palindromic Substrings Given a string s, return the number of palindromic substrings 回文子串 in it. A string is a palindrome when it reads the same backward as forward. A substring is a contiguous sequence of characters within the string. nomal: …

LeetCode //C - 221. Maximal Square

221. Maximal Square Given an m x n binary matrix filled with 0’s and 1’s, find the largest square containing only 1’s and return its area. Example 1: Input: matrix [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,…

图解Spark Graphx实现顶点关联邻接顶点的collectNeighbors函数原理

一、场景案例 在一张社区网络里&#xff0c;可能需要查询出各个顶点邻接关联的顶点集合&#xff0c;类似查询某个人关系比较近的都有哪些人的场景。 在用Spark graphx中&#xff0c;通过函数collectNeighbors便可以获取到源顶点邻接顶点的数据。 下面以一个例子来说明&#…

C语言--每日选择题--Day37

第一题 1. 有以下说明语句&#xff1a;则下面引用形式错误的是&#xff08;&#xff09; struct Student {int num;double score; };struct Student stu[3] {{1001,80}, {1002,75}, {1003,91}} struct Student *p stu; A&#xff1a;p->num B&#xff1a;(p).num C&#…

[论文精读]序列建模使大视觉模型的规模化学习成为可能

本博客是一篇最新论文的精读&#xff0c;论文为UC伯克利大学及约翰霍普金斯大学相关研究者新近(2023.12.1)在arxiv上上传的《Sequential Modeling Enables Scalable Learning for Large Vision Models》 。知名科技新媒体“新智元”给与本文极高评价&#xff0c;并以《计算机视…

STM32(PWM、ADC)

1、PWM 定义 PWM&#xff0c;全称为脉冲宽度调制&#xff08;Pulse Width Modulation&#xff09;&#xff0c;它通过改变信号的高电平和低电平的持续时间比例来控制输出信号的平均功率或电压。 PWM&#xff0c;全称为脉冲宽度调制&#xff08;Pulse Width Modulation&#xff…

FPGA实现电机位置环、速度环双闭环PID控制

一、设计思路 主要设计思路就是根据之前写的一篇FPGA实现电机转速PID控制&#xff0c;前面已经实现了位置环的控制&#xff0c;思想就是通过电机编码器的当前位置值不断地修正PID去控制速度。 那为了更好的实现控制&#xff0c;可以在位置环后加上速度环&#xff0c;实现电机位…

scipy

scipy 是什么常用方法 是什么 scipy是Python语言的一个开源数值计算库&#xff0c;主要目的是为科学、工程、计算等领域提供有用的数学算法和函数&#xff0c;包括线性代数、优化、信号处理、傅里叶变换、统计函数等。它是Python科学计算环境的重要组成部分&#xff0c;通常与N…

2021年GopherChina大会-核心PPT资料下载

一、峰会简介 自 Go 语言诞生以来&#xff0c;中国便是其应用最早和最广的国家之一&#xff0c;根据 Jetbrains 在 2021 年初做的调查报告&#xff0c;总体来说目前大概有 110 万专业的开发者 选择 Go 作为其主要开发语言。就其全球分布而言, 居住在亚洲的开发者最多&#xff…

go学习之goroutine和channel

文章目录 一、goroutine(协程)1.goroutine入门2.goroutine基本介绍-1.进程和线程说明-2.程序、进程和线程的关系示意图-3.Go协程和Go主线程 3.案例说明4.小结5.MPG模式基本介绍6.设置Golang运行的CPU数7.协程并发&#xff08;并行&#xff09;资源竞争的问题8.全局互斥锁解决资…

MySQL 8 update语句更新数据表里边的数据

数据重新补充 这里使用alter table Bookbought.bookuser add userage INT after userphone;为用户表bookuser在userphone列后边添加一个类型为INT的新列userage。 使用alter table Bookbought.bookuser add sex varchar(6) after userage ;为用户表bookuser在userage 列后边添…

Oracle-数据库连接数异常上涨问题分析

问题&#xff1a; 用户的数据库在某个时间段出现连接数异常上涨问题&#xff0c;时间持续5分钟左右&#xff0c;并且问题期间应用无法正常连接请求数据库 从连接数的监控上可以看到数据库平常峰值不到100个连接&#xff0c;在问题时间段突然上涨到400以上 问题分析&#xff1a;…

unity | 动画模块之循环滚动选项框

一、作者的话 评论区有人问&#xff0c;有没有竖排循环轮播选项框&#xff0c;我就写了一个 二、效果动画 如果不是你们想要的&#xff0c;就省的你们继续往下看了 三、制作思路 把移动分成里面的方块&#xff0c;还有背景&#xff08;父物体&#xff09;&#xff0c;方块自…

网络模拟与网络仿真

目录 一、概念界定 二、模拟&#xff08;simulation&#xff09;与仿真&#xff08;emulation&#xff09; 2.1 模拟&#xff08;simulation&#xff09; 2.2 仿真&#xff08;emulation&#xff09; 2.3 区分 三、网络模拟与网络仿真 3.1 网络模拟 3.2 网络仿真 3.…

【算法】算法题-20231206

这里写目录标题 一、非自身以外数字的乘积二、最大数三、奇数排序 一、非自身以外数字的乘积 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀…