Java 与排序算法(3):插入排序

news2025/1/17 0:17:31

一、插入排序

插入排序(Insertion Sort)是一种简单直观的排序算法,它的基本思想是将待排序序列分为已排序区间和未排序区间,然后每次从未排序区间取出一个元素,将其插入到已排序区间的合适位置中,使得插入后仍然保持已排序区间有序。重复这个过程,直到未排序区间为空,整个序列有序为止。

具体来说,插入排序的实现可以分为两个步骤:

  1. 将待排序序列分为已排序区间和未排序区间。初始时,已排序区间只包含第一个元素,而未排序区间包含剩余的所有元素。
  2. 从未排序区间取出一个元素,将其插入到已排序区间的合适位置中。插入时,我们从已排序区间的末尾开始比较,找到插入位置后将其插入,并将已排序区间的元素向后移动一位。

    在这里插入图片描述

二、插入排序的性质

插入排序的性质包括:

  1. 稳定性:插入排序是一种稳定排序算法,即相等的元素在排序前后的相对位置不变。

  2. 原地排序:插入排序是一种原地排序算法,即不需要额外的空间来存储排序结果,只需要在原数组上进行操作即可。

  3. 最好情况时间复杂度:当待排序序列已经有序时,插入排序的时间复杂度为 O(n),即最优情况下的时间复杂度。

  4. 最坏情况时间复杂度:当待排序序列是逆序的时,插入排序的时间复杂度为 O(n^2),即最坏情况下的时间复杂度。

  5. 平均情况时间复杂度:插入排序的平均情况时间复杂度为 O(n^2)。

  6. 适用性:插入排序适用于小规模的数据排序,对于大规模数据排序效率较低。在实际应用中,插入排序通常用作其他排序算法的辅助排序算法,例如快速排序的子过程。

三、插入排序的变种

插入排序有多种变种,以下是几种常见的变种:

  1. 希尔排序(Shell Sort):希尔排序是插入排序的改进版,它通过将待排序序列分成多个子序列,分别进行插入排序,最后再进行一次整体的插入排序,从而提高了排序效率。希尔排序的时间复杂度为 O(nlogn) ~ O(n^2)。

  2. 折半插入排序(Binary Insertion Sort):折半插入排序是插入排序的一种优化,它利用二分查找来寻找插入位置,从而减少了比较次数。折半插入排序的时间复杂度为 O(n^2)。

  3. 带哨兵的插入排序(Insertion Sort with Sentinel):带哨兵的插入排序是插入排序的一种优化,它通过在待排序序列的首位增加一个哨兵元素,从而避免了每次插入时的边界判断,提高了排序效率。带哨兵的插入排序的时间复杂度与普通插入排序相同,都为 O(n^2)。

  4. 双向插入排序(Two-way Insertion Sort):双向插入排序是插入排序的一种改进,它同时从前后两个方向遍历待排序序列,从而减少了比较次数和交换次数。双向插入排序的时间复杂度为 O(n^2)。

  5. 链表插入排序(Insertion Sort for Linked List):链表插入排序是插入排序的一种适用于链表的变种,它通过遍历链表,将每个节点插入到已排序链表的合适位置中,从而实现链表的排序。链表插入排序的时间复杂度为 O(n^2)。

总之,插入排序的变种有很多,每种变种都有其适用的场景和优缺点,选择合适的排序算法取决于具体的应用场景和需求。

四、Java 实现

以下是 Java 实现插入排序的示例代码:

public static void insertionSort(int[] arr) {
    int n = arr.length;
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

在这个实现中,我们使用了一个外层循环来遍历待排序序列,从第二个元素开始,依次取出每个元素;内层循环从当前元素的前一个位置开始,依次比较已排序区间中的元素,找到插入位置后将其插入。重复这个过程,直到整个序列有序为止。

使用示例:

int[] arr = {4, 2, 1, 5, 3};
insertionSort(arr);
System.out.println(Arrays.toString(arr)); // 输出 [1, 2, 3, 4, 5]

在这个示例中,我们定义了一个数组 arr,使用插入排序对其进行排序,并输出排序结果。

五、插入排序的应用场景

插入排序适用于以下场景:

  1. 数据规模较小:插入排序的时间复杂度为 O(n^2),对于数据规模较小的排序任务,插入排序的效率较高。

  2. 数据基本有序:当待排序序列基本有序时,插入排序的时间复杂度可以达到 O(n),即最优情况下的时间复杂度,因此插入排序在这种情况下的效率非常高。

  3. 辅助排序算法:插入排序通常用作其他排序算法的辅助排序算法,例如快速排序的子过程。

  4. 链表排序:插入排序是一种适用于链表的排序算法,因为链表的节点可以通过指针直接插入到已排序链表的合适位置中,从而避免了数组排序时的元素移动操作。

插入排序适用于数据规模较小、数据基本有序、辅助排序算法和链表排序等场景,但对于大规模数据排序,效率较低,因此在实际应用中需要根据具体情况选择合适的排序算法。

六、插入排序在spring 中的应用

在 Spring 框架中,插入排序主要用于 BeanFactory 的初始化工作中,即对 BeanDefinitionMap 中的 BeanDefinition 进行排序。

在 Spring 中,BeanDefinitionMap 是一个 Map 类型的数据结构,其中包含了所有的 BeanDefinition。当 Spring 容器启动时,需要对 BeanDefinition 进行排序,以便在后续的 Bean 实例化过程中能够正确地解析依赖关系。

为了实现 BeanDefinition 的排序,Spring 使用了插入排序算法。具体来说,Spring 使用了一个名为 SimpleAliasRegistry 的类来管理 BeanDefinition,其中包含了一个名为 singletonObjects 的 Map,用于存储已经实例化的单例 Bean。在初始化 BeanFactory 时,Spring 会对 BeanDefinition 进行排序,并按照排序后的顺序依次实例化 Bean,并将其存储到 singletonObjects 中。

以下是 Spring 中插入排序的示例代码:

public class SimpleAliasRegistry implements AliasRegistry {
    private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

    private final List<String> singletonCurrentlyInCreation = new ArrayList<>(16);

    private volatile boolean singletonsCurrentlyInDestruction = false;

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    // ...

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        this.beanDefinitionMap.put(beanName, beanDefinition);
        this.frozenBeanDefinitionNames = null;
    }

    public void preInstantiateSingletons() throws BeansException {
        List<String> beanNames = new ArrayList<>(this.beanDefinitionMap.keySet());
        // 对 BeanDefinition 进行排序
        Collections.sort(beanNames, new Comparator<String>() {
            @Override
            public int compare(String beanName1, String beanName2) {
                return getPriority(beanName1) - getPriority(beanName2);
            }
        });
        // 依次实例化 Bean
        for (String beanName : beanNames) {
            BeanDefinition bd = this.beanDefinitionMap.get(beanName);
            if (bd.isSingleton()) {
                if (bd.isLazyInit()) {
                    this.registerLazyInit(beanName, bd);
                } else {
                    this.getBean(beanName);
                }
            }
        }
    }

    // ...
}

在这个示例代码中,我们可以看到 Spring 中使用了插入排序算法对 BeanDefinition 进行排序,并按照排序后的顺序依次实例化 Bean。

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

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

相关文章

【SpringBoot】八:Web服务---WebMvcConfigurer

文章目录 1.WebMvcConfigurer简介2. 页面跳转控制器3. 数据格式化4. 拦截器4.1 一个拦截器4.2 多个拦截器 1.WebMvcConfigurer简介 WebMvcConfigurer是SpringMVC xml配置文件的JavaConfig实现方式。 2. 页面跳转控制器 创建 SpringMVC 配置类: 3. 数据格式化 Formatter&…

计算机组成原理-存储系统-主存储器(芯片)和CPU连接

目录 一、SRAM和DRAM芯片 DRAM&#xff1a;栅极电容存储信息 SRAM&#xff1a;双稳态触发器存储信息 区别​编辑 二、ROM芯片 三、主存于CPU的连接 位扩展法 字扩展法 字位同时扩展法 译码器 四、双端口RAM和多模块存储器 4.1双端口RAM 4.2多模块存储器 4.2.1单体多字…

pthread多线程: 创建最简单的线程

文章目录 1. 目的1.1 不使用 Pthread 的情况1.2 使用 Pthread 的情况1.3 使用 Pthread 的好处 2. Pthread 创建线程的 API2.1 环境2.2 pthread_create()2.3pthread_join() 3. 创建最简单的线程3.1 要点3.2 代码 4. 创建多个子线程4.1 要点4.2 代码 5. 总结 1. 目的 Pthread 提…

计算机组成原理-存储系统-基本概论及组成

目录 一、存储器的层次化结构 二、存储器分类 存储介质 存取方式 信息可改性 三、性能指标 四、主存储器基本组成 基本的的半导体元件及原理 存储芯片的基本原理 一、存储器的层次化结构 二、存储器分类 存储介质 半导体存储器(主存&#xff0c;cache)、磁表面存储器(…

基于SpringBoot的SSMP的整合案例

基于SpringBoot的SSMP的整合案例 简单介绍模块创建创建实体类导入Mybatis-plus和druid的配置文件使用junit测试查询方法MP分页查询按照条件进行查询业务层Service开发业务层Service快速开发表现层开发表现层 实现分页查询表现层消息一致性的处理查询所有书本信息添加书本删除操…

TensorFlow巨浪中的巨人:大数据领域的引领者 TensorFlow实战【上进小菜猪大数据系列】

上进小菜猪&#xff0c;沈工大软件工程专业&#xff0c;爱好敲代码&#xff0c;持续输出干货。欢迎订阅本专栏&#xff01; 大数据时代的到来带来了海量数据的处理和分析需求。在这个背景下&#xff0c;TensorFlow作为一种强大的深度学习框架&#xff0c;展现了其在大数据领域…

fastreport使用教程(fastreport报表编辑器)

除了库本身&#xff0c;FastReport.Net还包括单独的程序 – Designer和Viewer。 如您所知&#xff0c;第一个用于创建和编辑报表模板。它具有报表预览模式&#xff0c;您可以从中查看报表&#xff0c;将其导出为所需的数据格式并将其发送到打印。 Viewer用于以fpx预览格式查看报…

清华p-tuning | GPT也能做NLU?清华推出p-tuning方法解决GPT系列模型fine-tuning效果比BERT差问题

一、概述 title&#xff1a;GPT Understands, Too 论文地址&#xff1a;https://arxiv.org/abs/2103.10385 代码&#xff1a;https://github.com/THUDM/P-tuning 1.1 Motivation GPTs模型利用传统的fine-tuning技术在NLU任务上效果比较差&#xff0c;比同等量级的BERT效果…

2023/5/22总结

继承 继承是面向对象三大特征之一。可以使得子类具有父类的属性和方法&#xff0c;还可以在子类中重新定义&#xff0c;追加属性和方法。 如图&#xff1a; 在上面的图片中&#xff0c;dog和cat都继承了Animal类&#xff0c;所以dog和cat都可以称为Animal的子类或者派生类&…

chatgpt赋能Python-python_dng

Python DNG&#xff1a;开启更高效的数据处理之路 什么是Python DNG&#xff1f; Python DNG&#xff08;Data NumPy Generator&#xff09;是一种基于Python的高效数据生成器&#xff0c;可以加速数据处理和分析的过程。它基于Numpy数组操作和并行计算思想&#xff0c;可以快…

C++详解NOI题:[NOIP2021] 报数

文章目录 前言一、题目二、暴力解题步骤&#xff08;50分&#xff09;三、打表防坑解题&#xff08;100分&#xff09;总结 前言 受不了CSDN每日一练的在线竞赛系统了&#xff0c;bug多就算了&#xff0c;勉强能用&#xff0c;可那些题目的神描述&#xff0c;到处是错。所以找…

前端面试知识点总结

前言&#xff1a; 博主突击两个月八股拿到美团&#xff08;基础研发&#xff09;&#xff0c;腾讯&#xff08;IEG&#xff09;&#xff0c;百度&#xff08;搜索部门&#xff09;暑期实习offer call&#xff0c;这是我学习过程中整理的前端知识点&#xff0c;内容有些多&#…

【13900k】i9 核显升级驱动

这里写自定义目录标题 官方的助手不能用显卡控制中心提示最新的更新搜索显卡 intel uhd graphics 770 手动下载安装自定义音频为啥也要卸载&#xff1f;新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片…

网络编程——嵌入式(驱动)软开基础(六)

1、简述TCP三次握手的过程。 (1)第一次握手:客户端创建传输控制块,然后向服务器发出连接请求报文(将标志位SYN置1,随机产生一个序列号seq=x),接着进入SYN-SENT状态。 (2)第二次握手:服务器收到请求报文后由SYN=1得到客户端请求建立连接,回复一个确认报文(将标志…

进程启动后到加载Activity的流程源码解析(基于安卓版本28)

文章目录 源码解析总体时序图关键类解析ActivityThreadApplicationThreadInstrumentationClientTransactionActivityStackSupervisorActivityRecord梳理概述源码流程梳理 源码解析 总体时序图 关键类解析 只针对流程中用到的关键类进行解析。 ActivityThread 注意其父类是&…

ES6升级之路:探究模板字符串、startsWith()方法和endsWith()方法、repeat()等新特性。

模版字符串 ES6新增的创建字符串的方式,使用反引号定义 示例 <script>// 1.模板字符串可以解析变量 ${}显示变量的值let name 张三;let sayHello HEllo,我的名字叫${name};console.log(name);console.log(sayHello);let result {name: "zhangsan",age: 20…

Java【TCP 协议2】确认应答、超时重传机制

文章目录 前言一、确认应答1, 什么是确认应答2, 序列号和确认应答号 二、超时重传1, 什么是超时重传 总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系…

python基础(循环语句 while循环、break、continue,字符格式化,运算符)

1. while循环 【1】语法&#xff1a; while 条件:.........举例&#xff1a; print("123") while 条件:......... print(456)【2】循环语句的基本使用 示例1&#xff1a; print("开始") while True:print("hello world") print("结束&…

约瑟夫问题的环形链表实现[Java]

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601;…

(全网最详细攻略)【Crypto++】在Visual studio2022中运行Cryptopp

文章目录 前言一、Cryptopp是什么&#xff1f;1. Cryptopp&#xff08;CRYPTO&#xff09;官方文档wiki 二、下载Cryptopp2. Crypto下载地址3. 下载PEM包 三、在VS2022中使用Cryptopp库4. 处理crypto源文件5. 在VS2022项目中使用crypto库 四、运行代码后一些关于c的错误总结 前…