三种插入排序详解和代码实现(直接插入排序、折半插入排序和希尔排序)

news2024/9/20 16:33:31

目录

  • 基本思想
  • 直接插入排序
    • 排序方法
    • 代码实现
    • 复杂度分析
  • 折半插入排序
    • 排序方法
    • 代码实现
    • 复杂度分析
  • 希尔排序
    • 排序方法
    • 代码实现
    • 复杂度分析
      • 最佳情况
      • 平均情况
      • 最坏情况
      • 增量序列的影响

基本思想

插入排序的基本思想是:每一趟将一个待排序的元素按照其关键字的大小插入到已经排好序的一组数据的适当位置,直到所有的待排序元素全部插入为止。
就像我们在打扑克时,每抓取一张牌,都将其插入到合适的位置,直到所有的牌摸完,我们就得到了一个有序的序列。

本文介绍三种插入排序的方法:直接插入排序折半插入排序希尔排序

直接插入排序

排序方法

  1. 将待排序的元素存放在数组中,数据元素的数量为 n n n
    1

  2. 每次选择一个元素将其放到前面的有序数组中,使得其仍然保持有序。共循环 n − 1 n-1 n1 次,第 k k k 次循环之后有序数组的长度为 k + 1 k+1 k+1
    2

代码实现

public class Test {
    public static void insertSort(int[] a) {
        for (int i = 1; i < a.length; i ++) {
            int key = a[i];
            int j = i - 1;
            // 数组元素后移直到key找到合适的位置
            while (j >= 0 && a[j] > key) {
                a[j + 1] = a[j];
                j --;
            }
            a[j + 1] = key;
        }
    }
    public static void main(String[] args) {
        int[] data = {5, 7, 4, 2, 0, 3, 1, 6};
        insertSort(data);
        for (int i : data) {
            System.out.print(i + " ");
        }
    }
}

复杂度分析

  1. 外层循环从 i = 1 i=1 i=1 开始,共执行了 n − 1 n-1 n1 次循环,内层循环中最坏情况下每次需要移动的次数为 O ( n ) O(n) O(n),因此时间复杂度为 O ( n 2 ) O(n^2) O(n2)
  2. 排序过程中只需要 O ( 1 ) O(1) O(1) 数量级的变量来记录状态,因此空间复杂度为 O ( 1 ) O(1) O(1)
  3. 直接插排由于在移动元素时可以是从后向前遍历移动,因此算法属于稳定排序。

折半插入排序

排序方法

  • 直接插入排序的基础上进行优化,在进行查找待插入元素位置操作的时候,我们可以利用二分法来实现(即折半查找)。

代码实现

public static void binaryInsertSort(int[] array) {
    for (int i = 1; i < array.length; i++) {
        int key = array[i];
        int left = 0;
        int right = i - 1;

        // 二分查找
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (key < array[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

        int j = i - 1;
        while (j >= left) {
            array[j + 1] = array[j];
            j--;
        }
        array[left] = key;
    }
}

复杂度分析

  1. 折半插入排序的对象移动次数和直接插入排序相同,依赖于对象的初始排列方式。由于折半插入排序只是减少了元素之间的比较次数,并没有改变元素的移动次数。因此折半插入排序的时间复杂度仍为 O ( n 2 ) O(n^2) O(n2)
  2. 其空间复杂度也和直接插入排序相同,为 O ( 1 ) O(1) O(1)
  3. 折半插入排序也属于稳定排序,但是由于用到了二分查找,所以只能应用于顺序结构,不能用于链式结构。

希尔排序

排序方法

希尔排序实质上是采用分组插入的方法,将整个待排序的数组分为若干组,从而减少直接插入排序的数据量,对每个分组分别进行直接插入排序,然后增加每个分组的数据量重新进行排序。直至所有分组合并为一组。

  1. 确定一个增量 d 1 d_1 d1 ,并把间隔为 d 1 d_1 d1 的数据分入同一组中,在各组进行直接插入排序。
  2. 第二趟取增量 d 2 d_2 d2 ,重复上述分组和排序。
  3. 以此类推,直到所取的增量 d i = 1 d_i=1 di=1 d t < d t − 1 < . . . < d 2 < d 1 d_t<d_{t-1}<...<d_2<d_1 dt<dt1<...<d2<d1),所有数据在同一组中直接插入排序为止。

  1. 如图所示,第一趟取增量 d 1 = 4 d_1=4 d1=4,所有间隔为 4 4 4 的元素分为同一组,并进行直接排序。
    1

  2. 第二趟取增量 d 2 = 2 d_2=2 d2=2,所有间隔为 2 2 2 的元素分为同一组,并进行直接排序。
    2

  3. 第三趟取增量 d 3 = 1 d_3=1 d3=1,所有元素分为同一组,并进行直接排序,排序完成。
    3

代码实现

public static void shellSort(int[] array) {
    int n = array.length;
    // 每次间隔折半
    for (int gap = n / 2; gap > 0; gap /= 2) {
    	// 同组元素直接插入排序
        for (int i = gap; i < n; i++) {
            int key = array[i];
            int j = i;
            while (j >= gap && array[j - gap] > key) {
                array[j] = array[j - gap];
                j -= gap;
            }
            array[j] = key;
        }
    }
}

复杂度分析

希尔排序的空间复杂度与上述两种排序相同,均为 O ( 1 ) O(1) O(1)
记录跳跃式的移动导致了希尔排序算法是不稳定的。

希尔排序的时间复杂度取决于所使用的增量序列(gap sequence)。以下是对希尔排序时间复杂度的详细分析

最佳情况

  • 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)(在某些特定的增量序列下,如Hibbard增量序列)
  • 描述:当增量序列优化得当时,希尔排序的性能接近于 O ( n l o g n ) O(nlogn) O(nlogn)。这意味着希尔排序在最优情况下的性能与归并排序相近。

平均情况

  • 时间复杂度 O ( n 3 2 ) − O ( n 5 4 ) O(n^\frac{3}{2})-O(n^\frac{5}{4}) O(n23)O(n45)
  • 描述:对于大多数常用的增量序列(如Shell增量序列、Knuth增量序列等),希尔排序的平均时间复杂度通常介于 O ( n 3 2 ) O(n^\frac{3}{2}) O(n23) O ( n 5 4 ) O(n^\frac{5}{4}) O(n45) 之间。

最坏情况

  • 时间复杂度 O ( n 2 ) O(n^2) O(n2)(例如,使用简单的增量序列,如 n 2 , n 4 , . . . , 1 \frac{n}{2},\frac{n}{4},...,1 2n4n...1
  • 描述:在使用不优化的增量序列时,希尔排序的时间复杂度可能会退化到 O ( n 2 ) O(n^2) O(n2),类似于简单插入排序的时间复杂度。

增量序列的影响

  1. Shell增量序列:初始增量为 n 2 \frac{n}{2} 2n,然后逐步减小到 1 1 1。时间复杂度为 O ( n 2 ) O(n^2) O(n2)
  2. Hibbard增量序列:增量为 1 , 3 , 7 , 15 , . . . , 2 k − 1 1, 3, 7, 15, ..., 2^k-1 1,3,7,15,...,2k1。时间复杂度为 O ( n 3 2 ) O(n^\frac{3}{2}) O(n23)
  3. Knuth增量序列:增量为 1 , 4 , 13 , 40 , 121 , . . . , 3 k − 1 2 1, 4, 13, 40, 121, ..., \frac{3^{k-1}}{2} 1,4,13,40,121,...,23k1。时间复杂度为 O ( n 5 4 ) O(n^\frac{5}{4}) O(n45)
  4. Sedgewick增量序列:例如, 1 , 5 , 19 , 41 , 109 , . . . 1, 5, 19, 41, 109, ... 1,5,19,41,109,... 时间复杂度为 O ( n 4 3 ) O(n^\frac{4}{3}) O(n34)

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

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

相关文章

Hadoop 分布式集群搭建

HDFS分布式集群搭建 一、部署规划1.1 进程规划1.2 软件规划1.3 用户规划1.4 目录规划 二、 搭建HDFS 分布式集群2.1 HDFS 集群配置2.1.1 下载安装 Hadoop2.1.2 修改 hadoop-env.sh 配置文件2.1.3 修改 core-site.xml 配置文件2.1.4 修改 hdfs-site.xml 配置文件2.1.5 修改 slav…

力扣刷题(1)

两数之和 两数之和-力扣 思路&#xff1a; 动态开辟一个数组&#xff0c;用来存放下标&#xff1b;两个for循环嵌套来判断&#xff0c;数组中的两个数相加是否与target相等若相等&#xff0c;则将 * returnSize赋值为2&#xff0c;表示数组中两个数&#xff0c;并将arr数组…

数学建模之数据分析【九】:数据清理总结

文章目录 一、什么是数据清理二、为什么数据清理很重要三、执行数据清洁的步骤四、如何执行数据清理五、数据清理的Python库实现5.1 数据检查与探索5.2 使用df.info()检查数据信息5.3 检查分类和数字列5.4 检查分类列中唯一值的总数5.5 执行数据清理的步骤5.5.1 删除所有上述不…

真的爽到了!Coze的黑神话 “循环“ 闪亮登场,啥都能循环,让你一次通关!

心心念念了很久&#xff0c;Coze工作流终于支持循环操作啦&#xff0c;泪奔~~ 看&#xff0c;就在工作流节点的“选择器”和“意图识别”当中偷偷摸摸地多了一个“循环” 这玩意可比批处理强太多了&#xff0c;批处理只能在当前节点循环&#xff0c;做一些简单的循环任务还不错…

【日记】狗尾巴草与暗恋(1519 字)

写在前面 消极内容注意 正文 好想吃火龙果。 下周会变得异常艰难。因为事情已经垒到天上去了&#xff0c;还要来检查。 上午&#xff0c;同事送了一点水果&#xff0c;我从来没见过。问了一下别人&#xff0c;有的说是灯笼果&#xff0c;有的说是菇凉果、姑娘果。搜了一下&am…

深入理解Elasticsearch:让搜索性能飞起来!

Elasticsearch 概述 Elasticsearch是一个基于lucene、分布式、通过Restful方式进行交互的近实时搜索平台框架。 ELK 技术栈是Elasticsearch、Logstash、Kibana三大开元框架首字母大写简称。 而Elasticsearch 是一个开源的高扩展的分布式全文搜索引擎&#xff0c; 是整个 ELK技术…

polarctf靶场[WEB]Don‘t touch me、机器人、uploader、扫扫看

目录 [web]Dont touch me 考点&#xff1a;查看源代码、前端 [web]机器人 考点&#xff1a;robot协议 工具&#xff1a;御剑&#xff0c;kali dirsearch [web]覆盖 考点&#xff1a;parse_str覆盖 [web]扫扫看 考点&#xff1a;目录扫描 工具&#xff1a;御剑、kali d…

【冒泡排序算法】输入n个数进行排序

要求&#xff1a;输入n个数进行排序 实现&#xff1a;使用冒泡排序算法&#xff0c;使用C语言实现 冒泡排序的基本原理&#xff1a; 比较相邻元素&#xff1a;从数组的开始位置&#xff0c;比较每对相邻的元素。如果前一个元素大于后一个元素&#xff0c;则交换它们。重复过…

数组基本知识2

目录 前言 二维数组 使用原因 定义二维数组 访问数组元素 实例 前言 上一篇&#xff0c;我简单的复习了一维数组&#xff0c;本篇讲述二维数组的基本知识&#xff0c;帮助大家预习和复习。 二维数组 使用原因 本质原因&#xff1a;一维数组&#xff0c;已经无法满足解决…

OSPF路由配置--单区域

目录 因为OSPF有很多重要的特殊区域和内容,所以划分为多篇博客来配置 一. 实验拓扑图 二. 实验配置 三. 实验验证: 因为OSPF有很多重要的特殊区域和内容,所以划分为多篇博客来配置 不理解OSPF路由动态协议的可以回顾一下OSPF详解&#xff0c;下这一系列的实验都不再做解…

SpringBoot集成kafka-消息转发@sendTo()注解

SpringBoot集成kafka-消息转发sendTo 1、消费者2、生产者3、实体类对象4、JSON工具类5、配置文件application.yml6、测试类7、测试 1、消费者 启动消费者进行消息监听&#xff0c;消费者A监听到生产者发送的消息使用sendTo()注解将消息转发给消费者B package com.power.consu…

在树莓派5上使用pytroch进行模型训练—全流程笔记

在树莓派上运行pytroch模型&#x1f680; 在完成了树莓派的一系列基础配置学习之后&#xff0c;按照规划&#xff0c;下一步要做的就是在树莓派上安装一个pytorch&#xff0c;尝试运行一下深度学习的模型&#xff0c;如果可以实现且准速度有一定保证的话&#xff0c;就可以作为…

代码随想录算法训练营第50天|卡码网 98. 所有可达路径

1.卡码网 98. 所有可达路径 题目链接&#xff1a;https://kamacoder.com/problempage.php?pid1170 文章链接&#xff1a;https://www.programmercarl.com/kamacoder/0098.所有可达路径.html#总结 1.图的存储 本题我们使用邻接表 或者 邻接矩阵都可以&#xff0c;因为后台数据…

掌握路演艺术:创新大赛路演稿撰写指南

如何在创新大赛中脱颖而出&#xff1f;一份精心准备的路演稿是关键 前言开场白&#xff1a;抓住注意力的第一步项目概述&#xff1a;清晰传达核心价值市场分析&#xff1a;展示项目的市场潜力商业模式与盈利计划&#xff1a;务实的策略团队介绍&#xff1a;展现团队的实力与文化…

vue3的nginx配置文件配置(nginx只配置前端vue3的nginx.conf文件)

1、本地的访问网址的链接 http://localhost:5173/official-website/ 2、程序的配置 3、nginx.conf配置 #user nobody; worker_processes 1;events {worker_connections 1024; }http {include mime.types;default_type application/octet-stream;log_format main…

全网最细springboot学习笔记—SpringBoot配置SSL(https)

文章主要内容大致为&#xff1a; SpringBoot配置SSL&#xff08;https&#xff09; SpringBoot全局异常处理 SpringBoot 404页面处理 接下来让我们一起探讨三大框架之一的springboot框架&#xff1a; SpringBoot配置SSL&#xff08;https&#xff09; SpringBoot可以通过在appl…

如何使用ssm实现基于java的电脑硬件库存管理系统

TOC ssm145基于java的电脑硬件库存管理系统jsp 第1章 绪论 1.1 课题背景 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。所…

第四十六篇,PID心法解读

猛回头&#xff0c;有近半年的时光没输出了&#xff0c;看着昨天加班调的PID数据&#xff0c;灵光闪现了一下&#xff0c;赶紧记录。 参数整定找最佳&#xff0c;从小到大顺序查   先是比例后积分&#xff0c;最后再把微分加 曲线振荡很频繁&#xff0c;比例度盘要放大   曲…

基于Open Cv的数字图像手势识别系统,Python编程实现,可以识别以下6种手势,含代码和报告

该项目的目标是设计并实现一个能够实时识别特定手势的系统。系统将使用OpenCV库来捕获视频流&#xff0c;并通过图像处理技术来识别特定的手势。具体来说&#xff0c;系统将识别以下六种手势&#xff1a; 挥手 - 手掌水平移动。握拳 - 手指全部弯曲成拳头。坐起 - 模拟做仰卧起…

sft是mean-seeking rl是mode-seeking

原文链接 KL散度是D(P||Q)&#xff0c;P和Q谁在前谁在后是有讲究的&#xff0c;P在前&#xff0c;就从P采样。 D K L ( P ∣ ∣ Q ) E x − p ( x ) ( l o g ( P ( x ) / Q ( x ) ) ) D_{KL}(P||Q)E_{x-p(x)}(log(P(x)/Q(x))) DKL​(P∣∣Q)Ex−p(x)​(log(P(x)/Q(x)))想象一…