【最简单最直观的排序 —— 插入排序算法】

news2024/11/6 7:18:24

【最简单最直观的排序 —— 插入排序算法】

插入排序是一种简单直观的排序算法。其基本思想是把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

插入排序的核心就是多趟选择插入。当插入第 i(i>=1)个元素时,前面的 array(0),array(1),…,array(i - 1)已经排好序,此时用 array(i)的排序码与 array(i - 1),array(i - 2),…的排序码顺序进行比较,找到插入位置即将 array(i)插入,原来位置上的元素顺序后移。
在这里插入图片描述

以升序排序为例,假若有 N 个数

第一次插入:因为第 0 个位置可以看作已经排好序了,将 array(1)看作是被插入的数据,即让被插入的数据与 (0, i ) 区间的元素数据相比,若遇到数据比被插入的数据要大,遇到的数据后移一位,若遇到数据比被插入的数据要小,就将被插入的数据插入到该数据的后面。这样排好之后,前两个数据就变得有序了。
第二次插入:i == 2,此时前两个数据是有序的,即是将 array(2)看作是被插入的数据,在往前进行观察选择插入……
最后一次插入:i==N - 1,此时前 N - 1 个数据是有序的,将 array(N - 1)看作是被插入的数据,在往前进行观察选择插入。这一趟选择插入之后,这整个数组序列就变得有序了。

以下是用 C 语言实现的插入排序代码示例:

#include<stdio.h>
// 插入排序
void InsertSort(int* a, int n)
{
    for (int i = 1; i < n; i++) // 决定所插入数据的位置 和 决定插入遍历的次数
    {
        int tem = a(i); // 被插入的数据
        int end = i - 1; // 决定 与被插入的数据相比较 的区间
        while (end >= 0) // 结束条件:全部数据比较完成,该循环目的是:找到比被插入数据要小的值的位置
        {
            if (a(end) > tem) // 已排好的数组中 end 的位置上的数 比 所要插入的数 大就交换
            {
                a(end + 1) = a(end); // 大数往后移一位
                end--; // end 往前走一步
            }
            else// 有数据比 被插入的数据要小,跳出循环
            {
                break;
            }
        }
        a(end + 1) = tem; // 将要插入的数插入到 end 位置的后一位。
    }
}
int main()
{
    int a() = { 29,10,14,37,12,6,32 };
    int sz = sizeof(a) / sizeof(a(0)); // 获取数组的大小
    printf("插入排序:\n");
    for (int i = 0; i < sz; i++) // 打印排序前的序列
    {
        printf("%d ", a(i));
    }
    printf("\n");
    InsertSort(a, sz); // 执行 插入排序 函数
    for (int i = 0; i < sz; i++) // 打印排序后的序列
    {
        printf("%d ", a(i));
    }
    printf("\n");
    return 0;
}

此外,插入排序还有多种语言的实现方式,如 Python:

def insertionSort(arr):
    for i in range(1, len(arr)):
        key = arr(i)
        j = i - 1
        while j >= 0 and key < arr(j) :
            arr(j + 1) = arr(j)
            j -= 1
        arr(j + 1) = key
arr = (12, 11, 13, 5, 6)
insertionSort(arr)
print ("排序后的数组:")
for i in range(len(arr)):
    print ("%d" %arr(i))

插入排序算法适用于少量数据的排序,时间复杂度为 O(n²),是稳定的排序方法。

插入排序算法的时间复杂度分析

插入排序的时间复杂度取决于待排序序列中元素的值。当待排序序列的长度为 n 时,最坏情况下的时间复杂度为 O(n²),因为每次插入都需要比较相邻的元素。例如,对于一个逆序排列的序列,每次插入新元素都需要与已排序部分的所有元素进行比较和移动。然而,在实际应用中,插入排序的平均时间复杂度也为 O(n²)。但在最好情况下,即排序表本身是有序的,此时只需比较 n - 1 次,没有移动的记录,时间复杂度为 O(n)。插入排序的时间复杂度分析主要基于其算法的基本操作,即每次从无序序列中取出一个元素,然后在已排序序列中找到合适的位置插入。这种操作在不同情况下的执行次数不同,导致了不同的时间复杂度表现。

插入排序算法的适用场景

插入排序通常用于小型数据集的排序。其排序过程类似于我们打牌时将手中的牌按照从小到大的顺序整理。插入排序的基本思想是将未排序的元素依次插入已排序的元素中,直到所有元素都有序。插入排序适用于以下场景:一是数据量较小的情况,例如量级小于千。在小型数据集上,插入排序的效率比较高,因为其时间复杂度虽然为 O(n²),但对于小规模数据,这个复杂度并不会造成太大的性能问题。二是若已知输入元素大致上按照顺序排列,此时插入排序效率较高。因为在这种情况下,插入排序的比较和移动操作会大大减少,时间复杂度接近最好情况的 O(n)。例如,对于一个已经部分有序的序列 [2, 4, 3, 5, 1],使用插入排序可以快速将其排序为 [1, 2, 3, 4, 5]

C 语言插入排序代码示例分析

以下是 C 语言插入排序的代码示例分析:

void _sort(int a[],int n)
{
    //进行 N-1 轮插入过程
    for(int i=1; i<n; i++)
    {
        //首先找到元素 a[i]需要插入的位置
        int j=0;
        while( (a[j]<a[i]) && (j<n))
            j++;
        //将元素 a[i]插入到正确位置
        int temp = a[i];
        for(int k=i; k>j; k--)
            a[k] = a[k-1];
        a[j] = temp;
    }
}

在这段代码中,首先进行N - 1轮插入过程。每一轮中,从无序序列中取出一个元素,即数组中的 a[i]。然后通过一个 while 循环找到这个元素在已排序序列中的正确位置 j。如果 a[j]小于 a[i],则继续寻找下一个位置;如果 a[j]大于等于 a[i],则找到了插入位置。接着,将从插入位置到当前元素位置之间的元素向后移动一位,为新元素腾出位置。最后,将新元素插入到正确位置 j。这个过程体现了插入排序的基本思想,即每次将一个未排序的元素插入到已排序的序列中,保持已排序序列的有序性。

Python 插入排序代码示例分析

以下是 Python 插入排序的代码示例分析:

def insert_sort(arr):
    # 从第二个元素开始循环,因为第一个元素默认是有序的
    for i in range(1, len(arr)):
        # 从后往前比较,如果当前元素比前一个元素小,就交换位置
        while i > 0 and arr[i] < arr[i - 1]:
            arr[i], arr[i - 1] = arr[i - 1], arr[i]
            i -= 1
    return arr

在这段 Python 代码中,首先从第二个元素开始遍历数组。对于每个元素,从当前位置开始向前面的已排序部分进行比较。如果当前元素小于前一个元素,就交换它们的位置,并继续向前比较,直到找到合适的位置插入当前元素。这个过程与插入排序的基本思想一致,通过不断地将未排序元素插入到已排序部分的正确位置,最终实现整个数组的有序排列。

总结

插入排序算法是一种简单直观的排序算法,适用于小型数据集或部分有序的情况。它具有稳定性,时间复杂度在最坏情况下为 O(n²),但在最好情况下为 O(n)。C 语言和 Python 的代码示例展示了插入排序的具体实现方式,通过比较和移动元素,将未排序的元素逐步插入到已排序的序列中。在实际应用中,根据数据规模和特点,可以选择插入排序或其他更高效的排序算法。

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

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

相关文章

python模块之getopt

getopt.getopt(args, shortopts, longopts[]) 解析命令行选项及参数列表。 args&#xff1a;要解析的参数列表&#xff0c;但不包括当前执行的python脚本名称&#xff0c;一般等同于sys.argv[1:]。 shortopts&#xff1a;要识别的短选项字符串&#xff0c;如果后接:表示需要…

C++入门day4-面向对象编程(下)

前言&#xff1a;C入门day3-面向对象编程&#xff08;中&#xff09;-CSDN博客 初识&#xff1a;继承特性 继承的基础语法 class A{ public:int a; }; class B:public A { public:int b; }; B类通过继承A类后&#xff0c;内部会继承一个int变量 a&#xff1a;从下图我们可以…

Mesa三角形光栅化过程关键代码

1.先看下mesa三角形光栅化效果 2.这里是主要实现代码&#xff0c;Mesa的代码也是非常多&#xff0c;看了好多天。关键实现过程代码这个s_tritemp.h中 3.这里主要介绍渲染一个矩形的过程 a)在glut中两行代码: b) 中间过程代码忽略&#xff0c;进入static GLboolean run_render(…

生活英语口语柯桥学英语“再确认一下“ 说成 “double confirm“?这是错误的!

在追求英语表达的过程中&#xff0c;我们常常会遇到一些看似合理实则错误的表达习惯。今天&#xff0c;我们就来聊聊一个常见的误区——“再确认一下”被误译为“double confirm”。 “再次确认”不是double confirm 首先&#xff0c;我们需要明确&#xff0c;“double confi…

POI从3.14升级为5.2.0

最近word用的功能有点多&#xff0c;3.14功能太少&#xff0c;升级一下。 从5.0.X开始&#xff0c;poi-ooxml–schemas被重命名为poi-ooxml–full 最新版是5.3.0&#xff0c;但是word转pdf的工具最新到poi的5.2.0&#xff0c;所以用这个版本了 properties中变量 <poi.versio…

在docker中找不到文件

问题 这是我的Dockerfile&#xff1a; FROM mcr.microsoft.com/dotnet/sdk:8.0 as build WORKDIR /app EXPOSE 80COPY TotechsThunder.sln TotechsThunder.sln COPY mock/programminglanguages/programminglanguage.js mock/programminglanguages/programminglanguage.js COP…

大觅网之业务部署(Business deployment of Da Mi Network)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

ubuntu20.04.6 触摸屏一体机,外接视频流盒子开机输入登录密码触屏失灵问题解决方法

1. 首先直接运行xrandr命令&#xff0c;查看设备的相关信息&#xff1a; 运行之后会显示当前连接设备的屏幕信息&#xff0c;如下图&#xff0c;LVDS和VGA-0&#xff0c;而HDMI屏幕为disconnect&#xff0c;意为没有连接&#xff1a; 2. 设置开机主屏幕显示&#xff1a; xrand…

TypeScript 设计模式之【建造者模式】

文章目录 **建造者模式**&#xff1a;打造你的梦想之屋建造者的秘密建造者有什么利与害&#xff1f;如何使用建造者搭建各种房子代码实现案例建造者模式的主要优点建造者模式的主要缺点建造者模式的适用场景总结 建造者模式&#xff1a;打造你的梦想之屋 假设你想要一栋完美的…

LeetCode[简单] 876. 链表的中间结点

给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 思路 对任意正整数 n&#xff0c;中间结点的编号可以表示成 ⌊2n​⌋1。 解法一 /*** Definition for singly-linked list.* public class L…

数据分析:线性回归计算嵌套的组间差异

文章目录 介绍加载依赖包导入数据数据预处理数据概览线性回归画图森林图的特点:森林图的作用:总结系统信息介绍 在统计学中,嵌套的组间差异分析是一种评估不同组别间差异的方法,尤其适用于层级结构或分组数据。通过线性回归模型,我们可以计算出各个变量对于因变量的影响,…

priority_queue优先级队列(堆)详解。C++经验+1

什么是堆 首先我们先了解什么是堆&#xff1f;堆分为大根堆和小根堆。但其实大根堆会让人误以为是不是大的元素在下面呢&#xff1f;为了防止错误想法&#xff0c;大根堆也可以叫大顶堆。 大顶堆&#xff1a;顶上元素最大&#xff0c;上一层比下一层元素大。 小顶堆&#xff…

AI搜索软件哪个好,AI搜索引擎工具分享

随着AI技术的发展&#xff0c;AI搜索引擎工具正逐渐成为我们信息获取的重要方法。下面小编就来和大家分享一些好用的AI搜索引擎软件&#xff0c;感兴趣的同学可以逐个使用体验一下。因为每个AI搜索引擎工具不同&#xff0c;建议大家搜索的时候可以多个工具搜索&#xff0c;然后…

.netcore nacos注册成功,服务列表找不到任何服务

命令空间id不要自动生成 .netcore 配置文件里&#xff0c;Namespace 配置命名空间id 而不是命名空间名称。

OrangePi 烧录镜像步骤

理解&#xff1a;第一步&#xff1a;烧录镜像。第二步&#xff1a;建立编译环境&#xff08;一般是PC端的Linux虚拟机&#xff09;和板卡端的文件连接。因为要传文件&#xff0c;一般用挂载的方法。第三步&#xff1a;软件程序的编译与部署。 第一步&#xff1a;烧录镜像步骤 …

React学习笔记(四)——React 组件生命周期

目录 1. 生命周期-概览 2. 生命周期-挂载阶段 3. 生命周期-更新阶段 4. 生命周期-卸载阶段 5. setState扩展-发现问题 6. setState扩展-更多用法 7. setState扩展-异步 1. 生命周期-概览 了解react类组件生命周期整体情况 大致步骤&#xff1a; 什么是生命周期React类组…

AntFlow-Vue3 :一个仿钉钉流程审批,且满足99.8%以上审批流程需求的企业级工作流平台,开源且免费!

在现代企业管理中&#xff0c;流程审批的高效性直接影响到工作的流畅度与生产力。最近&#xff0c;我发现了一个非常有趣的项目—— AntFlow-Vue3 。这个项目不仅提供了一个灵活且可定制的工作流平台&#xff0c;还能让用户以可视化的方式创建和管理审批流程。 如果你是一名前…

10. 排序

一、排序的概念及引用 1. 排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录…

Qt基础之四十七:管理员权限

在Windows系统中,以管理员身份运行的意思是,用系统管理最高权限运行程序。一般来说,只有当某些操作涉及系统保护区域时,才会需要用户授权管理员运行。如此一来,程序、命令在运行过程中,就有了足够权限,更改系统设置或注册表。 一.Qt程序加入管理员权限的几种方式 1.MS…

推荐一些免费下载恶意样本的网站

前一阵微步下载样本开始收费&#xff0c;算是又断了一个很好的白嫖途径。目前工作需求是不定期获取一批不同家族样本&#xff0c;看了看微步基础会员每天5次的下载限制&#xff0c;我默默把微步网页点了X&#xff0c;选择其他网站进行白嫖。 精确搜索 先列举出几个搜索比较简单…