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

直接插入排序【从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),也就是说它是一个原地排序算法。这也意味着直接插入排序非常节省内存,适合于在内存受限的环境中使用。

相关文章:

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

文章目录 &#x1f497; 直接插入排序Java代码C代码JavaScript代码稳定性时间复杂度空间复杂度 我们先来学习 直接插入排序, 直接排序算是所有排序中最简单的了,代码也非常好实现,尽管直接插入排序很简单,但是我们依旧不可以上来就直接写代码,一定要分析之后才开始写,这样可以提…...

C++/CLI——1简介

C/CLI——1简介 如果你是.net程序员&#xff0c;不免会用到C/C写的库。对于简单的调用&#xff0c;可以直接使用DllImport来完成就可以&#xff0c;详情可参考C#调用C/C从零深入讲解。但是对于复杂的C类和对象&#xff0c;尤其是类似于OCC的大型C项目&#xff0c;DllImport可能…...

C#实现串口通讯

1、官网下载Launch Virtual Serial Port Driver Virtual Serial Port Driver - create and emulate virtual COM port&#xff0c;开个虚拟串口&#xff1a; Pair模式&#xff08;一对&#xff0c;成双成对的意思&#xff0c;就是COM1向COM2传或者COM2向COM1,好比两台机器的CO…...

NLP论文阅读记录 - 以大语言模型为参考学习总结

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.相关工作2.1文本生成模型的训练方法2.2 基于LLM的自动评估2.3 LLM 蒸馏和基于 LLM 的数据增强 三.本文方法3.1 Summarize as Large Language Models3.1.1 前提3.1.2 大型语言模型作为参考具有…...

前端---资源路径

当我们使用img标签显示图片的时候&#xff0c;需要指定图片的资源路径&#xff0c;比如: <img src"images/logo.png">这里的src属性就是设置图片的资源路径的&#xff0c;资源路径可以分为相对路径和绝对路径。 1. 相对路径 从当前操作 html 的文档所在目录算…...

【2024考研】心情记录

今天是12.26日。距离24考研已经过去了2天&#xff0c;自认为缓过来了&#xff0c;故写下这篇文章。 25日早上简单过了一下答案&#xff0c;但实在是记不住答案了&#xff0c;不知道是我的脑子抵触还是怎的&#xff0c;像一块灰色的布遮住了我的记忆&#xff0c;羞于打开&#x…...

MySQL数据库日志管理和数据的备份及恢复

目录 MySQL日志管理 数据库备份的重要性 数据库备份的分类 从物理与逻辑的角度 从数据库的备份策略角度 常见的备份方法 物理冷备 专用备份工具mysqldump或mysqlhotcopy 启用二进制日志进行增量备份 第三方工具备份 MySQL完全备份与恢复 MySQL完全备份 物理冷备份与…...

node-schedule nodejs定时提醒(并判断段是否是工作日)

概述 工作中有个需求&#xff1a;在特定的时间发送一些消息&#xff0c;也就是说比如在每天的7点发送消息&#xff1a;该起床了。一开始我想用定时器每分钟每分钟的去查当前时间&#xff0c;但好像有点蠢&#xff0c;然后我找到了这个包 使用方法 安装 npm install node-sc…...

LeetCode 75| 前缀和

目录 1732 找到最高海拔 724 找到数组的中心下标 1732 找到最高海拔 class Solution { public:int largestAltitude(vector<int>& gain) {int res 0;int sum 0;for(int num : gain){sum num;res max(res,sum);}return res;} }; 时间复杂度O(n) 空间复杂度O(…...

智能,轻量,高效的爬虫工具 (爬虫宝第一代), HSpider

场景 之前玩爬虫宝一时爽&#xff0c;但是我很快发现了一个致命的问题。就是chat3.5 有时候误判&#xff0c;Claude2 是遇到大一点的html就无法解析&#xff0c;chat4 Api没有申请下来&#xff0c;chat3.5 误判这个可以纠正&#xff0c;但是每次爬取花费的钱都是2刀以上&#…...

IDEA Maven Helper插件 解决jar冲突

Jar包冲突报错 程序抛出java.lang.ClassNotFoundException异常&#xff1b; 程序抛出java.lang.NoSuchMethodError异常&#xff1b; 程序抛出java.lang.NoClassDefFoundError异常&#xff1b; 程序抛出java.lang.LinkageError异常等&#xff1b;Maven Jar包管理机制 在Maven项…...

装饰 Web3 项目的用户交互界面(Web3项目二实战之四)

用户交互界面是Web3项目必不可少的,毕竟,Web3项目最终是面向用户的,所以,Web3项目总得需要一个优美的UI界面,已达到用户在视觉上精彩盛宴。 诚然,一个Web3项目若到了用户交互界面,大体上,这个Web3项目也将告一段落了。 没错,Web3第二个项目,也将终结于本篇,顺势拉开…...

【数据库系统概论】第3章-关系数据库标准语言SQL(3)

文章目录 3.5 数据更新3.5.1 插入数据3.5.2 修改数据3.5.3 删除数据 3.6 空值的处理3.7 视图3.7.1 建立视图3.7.2 查询视图3.7.3 更新视图3.7.4 视图的作用 3.5 数据更新 3.5.1 插入数据 注意&#xff1a;插入数据时要满足表或者列的约束条件&#xff0c;否则插入失败&#x…...

理解io/nio/netty

一、io io即input/output&#xff0c;输入和输出 1.1 分类 输入流、输出流&#xff08;按数据流向&#xff09; 字节流&#xff08;InputStream/OutputStream&#xff08;细分File/Buffered&#xff09;&#xff09;、字符流(Reader/Writer&#xff08;细分File/Buffered/pu…...

旅游品牌网站搭建的作用是什么

我国旅游业规模非常高&#xff0c;各地大小旅游景区也是非常多&#xff0c;尤其节假日更是可以达到峰值&#xff0c;无论周边游还是外地游对所要去的景区&#xff0c;消费者总是需要来回了解很多&#xff0c;浏览器查或旅行社咨询等。 对旅游企业而言&#xff0c;传统线下方式…...

Linux操作系统——进程(五)环境变量

环境变量 有了我们前面的命令行参数的理解基础呢&#xff0c;我们下面进入环境变量这一个部分的内容的学习。 一般在我们安装一些开发工具尤其是有解释器的开发工具的时候&#xff0c;我们呢一般都要配置环境变量&#xff0c;可能都不太清楚自己为什么要配置环境变量&#xf…...

西门子博途怎么使用PID_Compact做pid调试

到目前为止&#xff0c;我已经在S7-1200中创建了一个可运行的PLC程序&#xff0c;并在Basic Panel中创建了一个HMI项目来操纵和操作该程序。 引文&#xff1a;博途工控人平时在哪里技术交流博途工控人社群 现在&#xff0c;我们该如何深入的让程序开始逐渐智能化呢&#xff0c…...

结构型模式 | 适配器模式

一、适配器模式 1、原理 适配器模式&#xff08;Adapter&#xff09;&#xff0c;将一个类的接口转换成客户希望的另外一个接口&#xff0c;使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式主要分为三类&#xff1a;类适配器模式、对象适配器模式、接口…...

基于Python的车牌识别系统实现

本文将以基于Python的车牌识别系统实现为方向&#xff0c;介绍车牌识别技术的基本原理、常用算法和方法&#xff0c;并详细讲解如何利用Python语言实现一个完整的车牌识别系统。 精彩专栏持续更新推荐订阅&#xff0c;收藏关注不迷路 微信小程序实战开发专栏 目录 引言车牌识别…...

时间序列预测模型介绍及使用经验总结

1. 时序预测背景 时序数据&#xff0c;就是序列随时间变化的数据。时间序列分析&#xff0c;一般有时域和频域两种分析方法。时序预测的本质是在时域和频域层面探索时间序列变化的内在规律。 下图描述的是时域&#xff08;temporal domain&#xff09;&#xff0c;横坐标是时…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...