直接插入排序【从0-1学数据结构】

文章目录

      • 💗 直接插入排序
      • Java代码
      • C代码
      • JavaScript代码
      • 稳定性
      • 时间复杂度
      • 空间复杂度

我们先来学习 直接插入排序, 直接排序算是所有排序中最简单的了,代码也非常好实现,尽管直接插入排序很简单,但是我们依旧不可以上来就直接写代码,一定要分析之后才开始写,这样可以提高自己写代码的准确率,整体流程下来,对知识的理解也会加深.

💗 直接插入排序

默认第一个元素为有序的,然后从无序序列中的最左边取元素,从有序序列的右到左依次比较,直到找到合适的位置,然后插入. (简言之: 从无序序列取第一个元素从左到右比较插入到有序序列合适的位置)


用生活中的例子来描述直接插入排序理解起来会更加容易,所以我们这里就用一个生活中常发生的事来类比学习吧,如果我们把直接插入排序用打扑克牌来模拟,会是怎样的效果呢?

现在就来试试吧~

使用玩扑克牌的例子来模拟直接插入排序是一个很好的主意,这个例子非常贴近直接插入排序的实际操作过程。让我们详细地通过这个例子来理解直接插入排序:

  1. 初始状态:你的手中还没有牌,而洗好的牌堆是无序的。
  2. 拿起第一张牌:从牌堆中拿起最上面的一张牌,这是你手中的第一张牌,所以它自然就是有序的。
  3. 继续摸牌:再次从牌堆中拿起最上面的一张牌。
  4. 比较和插入
    • 将这张新拿到的牌与手中已有的牌从右到左进行比较。
    • 如果新牌比正在比较的牌小,就将手中的这张牌向右移动一个位置,为新牌腾出空间。
    • 继续这个过程,直到找到一个牌位,那里的牌比新牌小或者没有牌了(也就是这张新牌是目前最小的)。
  5. 插入新牌:将新牌放入这个位置。
  6. 重复过程:继续从牌堆中拿牌,并重复上述比较和插入的过程,直到牌堆中的所有牌都被拿完并按顺序排列在手中。

这个过程很好地模拟了直接插入排序的逻辑。在每一步中,你都保证了手中的牌是有序的,通过找到合适的位置为新牌插入。这就是直接插入排序的精髓:一步步构建有序序列,直到所有元素都被正确地插入。

我们把上面的操作用图示来演示一下,进一步加深理解 , 假设现在的洗好的扑克牌为一组无序序列 : {6,4,9,1,10,2,8}

好,可以开始打牌了~

image-20231223214529977

Java代码

package src.boke;public class InsertSort {public static void main(String[] args){//无序序列int[] arr = {6,4,9,1,10,2,8};//调用直接排序方法insertSort(arr);//打印有序序列printArray(arr);}/*** 直接插入排序方法实现* @param arr 待排序序列/无序序列*/public static void insertSort(int[] arr){//对传进来的无序序列进行直接插入排序操作for (int i = 1; i < arr.length; i++) {//接收int[i] ,即摸到的牌int key = arr[i];int j  = i-1;for (; j >=0 ; j--) {if(arr[j]>key){arr[j+1] = arr[j];}else{break;}}arr[j+1] = key;}}/*** 打印素组的方法*/public static void printArray(int[] arr){for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] +" ");}}
}

C代码

#include <stdio.h>void insertSort(int arr[], int n) {for (int i = 1; i < n; i++) {int key = arr[i];int j = i - 1;// 将大于 key 的元素向右移动一个位置while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j--;}arr[j + 1] = key;}
}void printArray(int arr[], int n) {for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = {6, 4, 9, 1, 10, 2, 8};int n = sizeof(arr) / sizeof(arr[0]);insertSort(arr, n);printArray(arr, n);return 0;
}

JavaScript代码

function insertSort(arr) {for (let i = 1; i < arr.length; i++) {let key = arr[i];let j = i - 1;while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j--;}arr[j + 1] = key;}
}function printArray(arr) {console.log(arr.join(" "));
}// 测试
let arr = [6, 4, 9, 1, 10, 2, 8];
insertSort(arr);
printArray(arr);

稳定性

排序稳定性是排序算法的一个重要特性,它涉及相等元素的相对顺序在排序前后是否保持不变。

具体来说:

  • 稳定排序:如果一个排序算法在排序后保持了相等元素在原序列中的相对顺序,那么这个算法是稳定的。换句话说,如果两个具有相等关键字的元素在排序前是以某种顺序排列的,那么在排序后它们仍然以同样的顺序排列,这样的排序算法就被认为是稳定的。
  • 不稳定排序:如果排序算法不能保证相等元素的相对顺序,则称这种排序是不稳定的。在这种情况下,相等的元素可能会因排序过程而交换位置。

稳定性的重要性主要体现在当元素有多个字段进行排序时。在某些情况下,维持数据的初始顺序是重要的。例如,在对一组人按照出生日期排序后,可能需要对结果按姓名排序,如果使用稳定排序算法,那么同一天出生的人将按照他们原始的顺序(即按姓名的顺序)排列。

image-20231223221026657

image-20231223221237867

通过上述测试我们可以知道,当我们在比较key和arr[j] 的时候,如果取了 等号 ,那么此时就是不稳定的,如果没有取 等号 就是稳定的,所以直接插入排序是稳定的吗?

让我们详细解释一下为什么这样会发生:

  • 当使用 arr[j] > key 进行比较时,如果 arr[j] 等于 key,那么循环会停止,key 将被插入到 arr[j] 的后面。因此,原始数组中顺序相邻的、值相等的元素在排序后仍将保持相同的顺序,这保证了排序的稳定性。
  • 然而,如果使用 arr[j] >= key 进行比较,当 arr[j] 等于 key 时,排序过程仍会继续,尝试找到更前面的位置插入 key。这可能导致 key 被插入到其他相等元素的前面,从而改变了这些元素的相对顺序,这破坏了排序的稳定性。

结论 : 一个本身就稳定的排序你可以将其实现为不稳定的,但是一个本身就不稳定的排序你无法将其变成稳定的. 所以 : 直接插入排序是稳定的排序


时间复杂度

  • 直接插入排序的时间复杂度是 O(n^2)

直接插入排序的时间复杂度分析涉及到最好情况、平均情况和最坏情况。

  1. 最好情况时间复杂度:当输入数组已经是有序的,每次比较都不需要进行移位操作(因为每个元素已经是在其正确的位置上),直接插入排序只需要进行一次遍历来确认所有元素都已排序。因此,在这种情况下,时间复杂度是 O(n),其中 n 是数组的长度。
  2. 最坏情况时间复杂度:在最坏的情况下,数组完全逆序,即每次插入都需要将元素移动到数组的最前面。这就需要对于每个元素进行从 1 到 i(其中 i 是当前元素的索引)的比较和移动,因此需要的操作数接近于 1+2+3+…+(n−1),这是一个等差数列求和,总和是 O(n^2)。
  3. 平均情况时间复杂度:在平均情况下,元素需要移动的次数大约是数组长度的一半,因此平均情况时间复杂度也是O(n^2)。

空间复杂度

  • 你直接插入排序的空间复杂度是O(1)

直接插入排序的空间复杂度主要考虑的是算法在执行过程中需要额外使用的内存空间。

在直接插入排序中,所有的排序操作都是在原始数组上进行的,不需要额外的数组来存储数据。排序过程中唯一需要的额外空间是一个用于存储待插入元素的临时变量(比如 key)。除此之外,还需要少量的额外空间用于循环计数和索引存储。

由于这些额外空间的需求量不随待排序的数据量的增加而增加(也就是说,无论要排序多少数据,所需的额外空间量都是固定的),因此直接插入排序的空间复杂度是O(1),也就是说它是一个原地排序算法。这也意味着直接插入排序非常节省内存,适合于在内存受限的环境中使用。

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

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

相关文章

微软官方出品:GPT大模型编排工具,支持C#、Python等多个语言版本

随着ChatGPT的火热&#xff0c;基于大模型开发应用已经成为新的风口。虽然目前的大型模型已经具备相当高的智能水平&#xff0c;但它们仍然无法完全实现业务流程的自动化&#xff0c;从而达到用户的目标。 微软官方开源的Semantic Kernel的AI编排工具&#xff0c;就可以很好的…

设计模式(三)-结构型模式(6)-享元模式

一、为何需要享元模式&#xff08;Flyweight&#xff09;? 假如在网页中渲染这样的一个画面&#xff1a;大小不一的星星铺满了整个画布&#xff0c;并且都在不断的进行移动闪烁着。一批星星消失了&#xff0c;另一批又从另一边缘处出现。 要实现这样的渲染效果&#xff0c;在…

实习课知识整理2:用户登录及实现登录后用户名和头像的展示

接上一篇&#xff0c;当用户点击购买按钮后&#xff0c;还是未登录的状态&#xff0c;此时页面会跳转到登录页面&#xff0c;这时需要输入正确的用户名和密码&#xff0c;完成登录 1. 给登录按钮添加点击事件&#xff0c;并提交表单中的数据到后端 <form th:action"{/u…

Elasticsearch Reroute API 的使用

本文通过一个 Elasticsearch 集群中主分片分配不均衡的例子演示一下 Cluster reroute API 的使用。 对于 Elasticsearch 分片分配策略不了解的同学可以点一下关注&#xff0c;后面更文之后获取第一手资料。 环境信息 Windows 10 Elasticsearch 8.1 JDK17 初始集群状态 分片…

【JAVA面试题】什么是引用传递?什么是值传递?

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 前言 博客的正文部分可以详细介绍Java中参数传递的机制&#xff0c;强调Java是按值传递的&#xff0c;并解释了基本数据类型和对象引用在这种传…

鳄鱼目标检测数据集VOC格式100张

鳄鱼是一种生活在热带和亚热带地区的爬行动物&#xff0c;属于爬行纲鳄形目鳄鱼科。它们的体形庞大&#xff0c;有粗壮的四肢和强壮的尾巴&#xff0c;一般能长到2-6米长&#xff0c;体重可达500公斤以上。鳄鱼的皮肤粗糙&#xff0c;呈灰褐色或黑色&#xff0c;布满了坚韧的鳞…

XSKY星辰天合星海架构荣获 IT168 “2023 年度技术卓越奖”

近日&#xff0c;"2023 年度技术卓越奖"获奖名单公布&#xff0c;XSKY 星辰天合的星海架构&#xff08;XSEA&#xff0c;极速全共享架构&#xff09;获得行业 CIO/CTO 大咖、技术专家及 IT 媒体三方认可&#xff0c;成功入选&#xff01; “技术卓越奖”评选由国内著…

【Linux驱动】字符设备驱动程序框架 | LED驱动

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;Hello驱动程序⚽驱动程序框架⚽编程 &#x1f3c0;LED驱动⚽配置GPIO⚽编程驱动…

最小二乘法简介

最小二乘法简介 1、背景描述2、最小二乘法2.1、最小二乘准则2.2、最小二乘法 3、最小二乘法与线性回归3.1、最小二乘法与线性回归3.2、最小二乘法与最大似然估计 4、正态分布&#xff08;高斯分布&#xff09; 1、背景描述 在工程应用中&#xff0c;我们通常会用一组观测数据去…

电商数仓项目----笔记六(数仓ODS层)

ODS层的设计要点如下&#xff1a; &#xff08;1&#xff09;ODS层的表结构设计依托于从业务系统同步过来的数据结构。 &#xff08;2&#xff09;ODS层要保存全部历史数据&#xff0c;故其压缩格式应选择压缩比较高的&#xff0c;此处选择gzip。 &#xff08;3&#xff09;…

C++入门-【13-C++ 多维数组】

C 多维数组 C 支持多维数组。多维数组声明的一般形式如下&#xff1a; type name[size1][size2]...[sizeN]; 例如&#xff0c;下面的声明创建了一个三维 5 . 10 . 4 整型数组&#xff1a; int threedim[5][10][4]; 二维数组 多维数组最简单的形式是二维数组。一个二维数组&am…

用23种设计模式打造一个cocos creator的游戏框架----(二十三)中介者模式

1、模式标准 模式名称&#xff1a;中介者模式 模式分类&#xff1a;行为型 模式意图&#xff1a;用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间的交互。 结构图&#xff…

竞赛保研 基于GRU的 电影评论情感分析 - python 深度学习 情感分类

文章目录 1 前言1.1 项目介绍 2 情感分类介绍3 数据集4 实现4.1 数据预处理4.2 构建网络4.3 训练模型4.4 模型评估4.5 模型预测 5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于GRU的 电影评论情感分析 该项目较为新颖&#xff0c;适合作为竞…

Linux基本指令(一)

前言 基本知识 文件文件内容文件属性(对文件的操作就是对这两部分进行操作) 在Linux中以 . 开头的文件叫隐藏文件 以-开头的是普通文件 以d开头的是目录文件 几个指令 先快速认识几个指令&#xff0c;方便后续的详细介绍 whoami 查看当前使用Linux系统的用户是谁 pwd …

要参加微软官方 Copilot 智能编程训练营了

GitHub Copilot 是由 GitHub、OpenAI 和 Microsoft 联合开发的生成式 AI 模型驱动的。 GitHub Copilot 分析用户正在编辑的文件及相关文件的上下文&#xff0c;并在编写代码时提供自动补全式的建议。 刚好下周要参加微软官方组织的 GitHub Copilot 工作坊-智能编程训练营&…

【51单片机系列】C51中的中断系统扩展实验

本文是关于51单片机中断系统的扩展实验。 文章目录 一、 扩展实验一&#xff1a;使用外部中断0控制蜂鸣器&#xff0c;外部中断1控制直流电机二、扩展实验二&#xff1a;修改定时器初值&#xff0c;设定3秒钟的定时时间让LED模块闪烁三、扩展实验三&#xff1a;使用定时器1和数…

法线贴图实现地形模型皱褶、凹凸不平的纹理效果

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 法线贴图在3D建模中扮演着重要的角色&#xff0c;它通过模拟表面的微…

(十七)Flask之大型项目目录结构示例【二扣蓝图】

大型项目目录结构&#xff1a; 问题引入&#xff1a; 在上篇文章讲蓝图的时候我给了一个demo项目&#xff0c;其中templates和static都各自只有一个&#xff0c;这就意味着所有app的模板和静态文件都放在了一起&#xff0c;如果项目比较大的话&#xff0c;这就非常乱&#xf…

Canal使用详解

Canal介绍 Canal是阿里巴巴开发的MySQL binlog增量订阅&消费组件&#xff0c;Canal是基于MySQL二进制日志的高性能数据同步系统。在阿里巴巴集团中被广泛使用&#xff0c;以提供可靠的低延迟增量数据管道。Canal Server能够解析MySQL Binlog并订阅数据更改&#xff0c;而C…

springboot集成websocket全全全!!!

一、界面展示 二、前置了解 1.什么是websocket WebSocket是一种在单个TCP连接上进行全双工通信的持久化协议。 全双工协议就是客户端可以给我们服务器发数据 服务器也可以主动给客户端发数据。 2.为什么有了http协议 还要websocket 协议 http协议是一种无状态&#xff0c;非…