直接插入排序【从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.mzph.cn/news/241822.shtml

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

相关文章

统计和绘图软件GraphPad Prism mac功能特点

GraphPad Prism mac是一款专业的统计和绘图软件&#xff0c;主要用于生物医学研究、实验设计和数据分析。 GraphPad Prism mac功能和特点 数据导入和整理&#xff1a;GraphPad Prism 可以导入各种数据格式&#xff0c;并提供直观的界面用于整理、编辑和管理数据。用户可以轻松…

大白鲨生成Windows木马(仅供参考不可实践)

一、学习方法 一个正确的学习方法往往比学习更为重要 方法一&#xff1a;学习技术的本质性作用 &#xff08;第一性定律&#xff09; — 帮助我们解决的问题是什么 — 产生的原因/价值 方法二&#xff1a;在工作中到底如何使用&#xff1f; 方法三&#xff1a;技术是由人…

【pynput】鼠标行为追踪并模拟

文章目录 前言基本思路安装依赖包实时鼠标捕获捕获鼠标位置捕获鼠标事件记录点击内容 效果图 利用本文内容从事的任何犯法行为和开发与本人无关&#xff0c;请理性利用技术服务大家&#xff0c;创建美好和谐的社会&#xff0c;让人们生活从繁琐中变得更加具有创造性&#xff01…

JavaScript状态模式

JavaScript状态模式 1 什么是状态模式2 使用状态模式改造电灯程序3 缺少抽象类的变通方式4 示例&#xff1a;文件上传4.1 场景描述4.2 代码过程 1 什么是状态模式 允许一个对象在其内部状态改变时改变它的行为&#xff0c;对象看起来似乎修改了它的类。 比如说这样一个场景&a…

【贪心】单源最短路径Python实现

文章目录 [toc]问题描述Dijkstra算法Dijkstra算法应用示例时间复杂性Python实现 个人主页&#xff1a;丷从心 系列专栏&#xff1a;贪心算法 问题描述 给定一个带权有向图 G ( V , E ) G (V , E) G(V,E)&#xff0c;其中每条边的权是非负实数&#xff0c;给定 V V V中的一个…

指南:在App Store Connect上编辑多个用户的访问权限

作为一名编程新手&#xff0c;在App Store Connect中管理用户权限可能初听起来有些复杂&#xff0c;但实际上它是一个相对直接的过程。这里是一个步骤清晰的指南来帮助您在App Store Connect上编辑多个用户的访问权限。 App Store Connect 简介 在开始之前&#xff0c;让我们…

Openwrt AP 发射 WiFi 信号

问题 想一次把 OpenWrt 路由器 wifi 问题给解决&#xff0c;完全取代路由器。 使用 倍控的 N5105 设备&#xff0c;有 mPCIe 接口&#xff0c;使用了 intel AX200 无线网卡&#xff0c;支持 2.4G 与 5G。 设置步骤 OpenWrt 镜像 第一次使用的镜像不支持 wifi&#xff0c;在…

“抓取再吸取的连续操作学习”研究工作发表于IEEE Trans. on Robotics:仿人手的柔性抓取,超人手的指背吸取!

长期以来&#xff0c;抓取一直被认为是机器人操作中一项重要而实际的任务。然而&#xff0c;实现对不同物体的稳健和有效的抓取具有挑战性&#xff0c;因为它涉及夹具设计、感知、控制和学习等。最近基于学习的方法在抓取各种新物体方面表现出优异的性能。然而&#xff0c;这些…

【C++11特性篇】新的类功能解读:新增加的[移动构造函数/移动赋值运算符重载]

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Linux》…

使用 Elasticsearch 检测抄袭 (二)

我在在之前的文章 “使用 Elasticsearch 检测抄袭 &#xff08;一&#xff09;” 介绍了如何检文章抄袭。这个在许多的实际使用中非常有意义。我在 CSDN 上的文章也经常被人引用或者抄袭。有的人甚至也不用指明出处。这对文章的作者来说是很不公平的。文章介绍的内容针对很多的…

Github 2023-12-24 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-24统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目5Jupyter Notebook项目2C项目1C项目1Go项目1Java项目1JavaScript项目1Ruby项目1 Serverless Frame…

双向长短期记忆网络(Bi-LSTM)-多输入回归预测

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分代码展示&#xff1a; 四、完整代码下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编…

vscode配置用户代码片段

1.左下角打开设置 2.新建全局代码片段 3.输入名字&#xff0c;名字随意不过最好语意化 4.创建模版 这里的模版为vue2常用代码片段&#xff0c;稍后会持续更新。 {"Print to console": {"prefix": "v2", //页面使用时名称"body":…

LeNet网络分析与demo实例

参考自 up主的b站链接&#xff1a;霹雳吧啦Wz的个人空间-霹雳吧啦Wz个人主页-哔哩哔哩视频这位大佬的博客 Fun_机器学习,pytorch图像分类,工具箱-CSDN博客 网络分析&#xff1a; 最好是把这个图像和代码对着来看然后进行分析的时候比较快 # 使用torch.nn包来构建神经网络. im…

Go 泛型之类型参数

Go 泛型之类型参数 文章目录 Go 泛型之类型参数一、Go 的泛型与其他主流编程语言的泛型差异二、返回切片中值最大的元素三、类型参数&#xff08;type parameters&#xff09;四、泛型函数3.1 泛型函数的结构3.2 调用泛型函数3.3 泛型函数实例化&#xff08;instantiation&…

WARNING: HADOOP_SECURE_DN_USER has been replaced by HDFS_DATANODE_SECURE_USER.

Hadoop启动时警告&#xff0c;但不影响使用&#xff0c;强迫症的我还是决定寻找解决办法 WARNING: HADOOP_SECURE_DN_USER has been replaced by HDFS_DATANODE_SECURE_USER. Using value of HADOOP_SECURE_DN_USER.原因是Hadoop安装配置于root用户下&#xff0c;对文件需要进…

案例144:基于微信小程序的自修室预约系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

Spring中的上下文工具你写的可能有bug

文章目录 前言功能第一种&#xff1a;ApplicationContext第二种方式&#xff1a;ApplicationContextAware第三种&#xff1a;BeanFactoryPostProcessor 源码第一种第二种第三种 前言 本篇是针对如何写一个比较好的spring工具的一个探讨。 功能 下面三种方式&#xff0c;你觉…

Odoo16 实用功能之Form视图详解(表单视图)

目录 1、什么是Form视图 2、Form视图的结构 3、源码示例 1、什么是Form视图 Form视图是用于查看和编辑数据库记录的界面。每个数据库模型在Odoo中都有一个Form视图&#xff0c;用于显示该模型的数据。Form视图提供了一个可编辑的界面&#xff0c;允许用户查看和修改数据库记…

[python]用python实现对arxml文件的操作

目录 关键词平台说明一、背景二、方法2.1 库2.2 code 关键词 python、excel、DBC、openpyxl 平台说明 项目Valuepython版本3.6 一、背景 有时候需要批量处理arxml文件(ARXML 文件符合 AUTOSAR 4.0 标准)&#xff0c;但是工作量太大&#xff0c;阔以考虑用python。 二、方…