手撕排序算法(一)——插入排序

news2024/10/7 18:31:38

排序的概念及意义

本章内容我们采用C语言完成代码。

排序的概念

我们先来了解一下基础概念:

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起

来的操作。

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记

录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍

在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

内部排序:数据元素全部放在内存中的排序。

外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据

的排序

了解完基本概念以后,为了便于理解,我们来举几个生活中的例子:

排序运用

下图是我们常用的购物软件,当我们购买选择商品时不可避免的要给商品排序。

示例一

又比如小伙伴们高考之后,分数太高,纠结于哪所大学,那么下图可以给我们答案。

示例二

插入排序

基本思想

直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐

个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

实际中我们玩扑克牌时,就用了插入排序的思想

原理

如图所示:

规律

1. 元素集合越接近有序,直接插入排序算法的时间效率越高

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1),它是一种稳定的排序算法

4. 稳定性:稳定

实现

void InsertSort(int* a, int n)
{
    // [0, end]有序  end+1位置的值插入[0, end],让[0, end+1]有序
    for (int i = 0; i < n - 1; ++i)
    {
        int end = i;
        //后一个值保存起来
        int tmp = a[end + 1];
        while (end >= 0)
        {
            if (a[end] > tmp)
            {
                a[end + 1] = a[end];
                --end;
            }
            else
            {
                break;
            }
        }
        a[end + 1] = tmp;
    }
}

希尔排序( 缩小增量排序 )

定义

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有

记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重

复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

希尔排序

特性总结

1. 希尔排序是对直接插入排序的优化。

2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的

了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的

对比。

比特就业课

3. 希尔排序的时间复杂度不好计算,需要进行推导,推导出来平均时间复杂度: O(N^1.3—

N^2)

4. 稳定性:不稳定

实现

其实跟前面的插入排序有异曲同工之妙,我们可以把插入排序中的gap看成一

void ShellSort(int* a, int n)
{
    int gap = n;

    while (gap > 1)
    {
        //gap = gap / 2;  // logN
        gap = gap / 3 + 1; // log3N 以3为底数的对数
        // gap > 1时都是预排序  接近有序
        // gap == 1时就是直接插入排序 有序

        // gap很大时,下面预排序时间复杂度O(N)
        // gap很小时,数组已经很接近有序了,这时差不多也是(N)

        // 把间隔为gap的多组数据同时排
        for (int i = 0; i < n - gap; ++i)
        {
            int end = i;
            int tmp = a[end + gap];
            while (end >= 0)
            {
                if (a[end] > tmp)
                {
                    a[end + gap] = a[end];
                    end -= gap;
                }
                else
                {
                    break;
                }
            }
            a[end + gap] = tmp;
        }
    }
}

注意:gap最好不要用固定值。但是要注意,如果为gap/3就要考虑能否被整除。

这里代码实现过程可能与小伙伴们想的有点不一样。

如图,‘9’跟‘4’换了之后,就直接‘1’和‘8’相比,也就是说这个是直接换完一组,然后接着换另外一组,直至换完。

测试

打印函数

我们可以设计出一个打印函数,这样可以方便我们测试。

//打印
void Print(int* a, int n)
{
    int i = 0;
    for (i = 0; i < n; i++)
    {
        printf("%d ", a[i]);
    }
    printf("\n");
}

测试排序

然后放入测试函数,我们首先测试一下插入排序:

void TestInsertSort1()
{
    int a[] = { 2,1,5,6,9,3,7,8 };
    InsertSort(a, sizeof(a) / sizeof(int));
    Print(a, sizeof(a) / sizeof(int));
}

结果:

再来测试一下希尔排序:

void TestInsertSort2()
{
    int a[] = { 2,1,5,6,9,3,7,8 };
    ShellSort(a, sizeof(a) / sizeof(int));
    Print(a, sizeof(a) / sizeof(int));
}

结果:

测试排序的性能

我们在测试速度的时候,可以讲vs中的解决方案配置从原来的Debug调成 Release。

在学习C语言的时候就已经提过,Release可以更加方便的完成计算。

// 测试排序的性能对比
void TestOP()
{
    srand(time(0));
    const int N = 100000;
    int* a1 = (int*)malloc(sizeof(int) * N);
    int* a2 = (int*)malloc(sizeof(int) * N);
    int* a3 = (int*)malloc(sizeof(int) * N);
    int* a4 = (int*)malloc(sizeof(int) * N);
    int* a5 = (int*)malloc(sizeof(int) * N);
    int* a6 = (int*)malloc(sizeof(int) * N);
    for (int i = 0; i < N; ++i)
    {
        a1[i] = rand();
        a2[i] = a1[i];
        a3[i] = a1[i];
        a4[i] = a1[i];
        a5[i] = a1[i];
        a6[i] = a1[i];
    }
    int begin1 = clock();
    InsertSort(a1, N);
    int end1 = clock();
    int begin2 = clock();
    ShellSort(a2, N);
    int end2 = clock();

    printf("InsertSort:%d\n", end1 - begin1);
    printf("ShellSort:%d\n", end2 - begin2);
    free(a1);
    free(a2);
}

总结

我们用C语言与小伙伴们以探讨了基础的插入排序和更加便捷的希尔排序,从而对排序有了一个基础的认知。

欢迎大家点赞和收藏。

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

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

相关文章

cin关闭流同步的利弊与cout的endl使用(超时问题)

重要&#xff1a;1&#xff1a;比如print&#xff0c;scanf&#xff0c;gets()&#xff0c;pus()&#xff0c;getchar()不要与cin&#xff0c;cout共用2&#xff1a;cout中不要使用endl每次使用endl&#xff0c;都要flush缓冲区&#xff0c;造成大量时间耗费。推荐cout <<…

springBoot国际化的一种方式

引言&#xff1a; 当我们的应用面向不同国家用户时&#xff0c;根据不同的locale返回不同的语言信息的国际化功能就显得有必要了。一般来说国际化主要表现在前端用户界面上&#xff0c;在现在前后端分离的背景下&#xff0c;前端页面的国际化交由前端代码独立完成&#xff1b;少…

只用两行代码做个表白二维码,赶快送给你心目中那个她吧♥(๑> ₃ <)♥

上一篇&#xff1a;教你一招完美解决 pptx 库安装失败的问题 今天有同事给我说&#xff1a;女朋友生日快到了&#xff0c;想用Python给她写个表白二维码&#xff0c;然后印在买的衣服上送给她。这么特别的生日礼物&#xff0c;博主还是第一次听到&#xff0c;不得不说&#xff…

Linux-make/Makefile

一、了解make/Makefile对于make/Makefile首先我们需要了解make是一条命令&#xff1b;Makefile是一个文件。make是一个命令&#xff0c;可以执行某条指令。这个我们理解&#xff0c;那Makefile是一个文件&#xff0c;那这个文件是干什么用的呢&#xff1f;这个文件内部一共包含…

SAP中新增销售科目配置分析实例

公司有一批呆滞维修用备件需要卖出&#xff0c;对应在系统内就需要做销售处理。但通常情况下&#xff0c;系统设计时没有考虑和配置备件销信也很正常。所以&#xff0c;处理时可能因为缺少配置做不下去。我需要解决配置问题&#xff0c;并做下可行性的测试。 首先考虑到的是末…

UniRx之ReactiveCommand

前言 UniRx中ReactiveCommand和AsyncReactiveCommand是一种基于IObservable的可控命令机制&#xff0c;用于控制是否允许进程运行 很难用文字说明&#xff0c;下面我们直接看代码吧 ReactiveCommand void Start() {//创建IObservable<bool>ReactiveProperty<bool&g…

分布式事务2种协议 及 4种模式

分布式事务协议 解决分布式事务&#xff0c;也有相应的规范和协议。分布式事务相关的协议有2PC、3PC。 由于三阶段提交协议3PC非常难实现&#xff0c;目前市面主流的分布式事务解决方案都是2PC协议。 2PC&#xff1a;两阶段提交协议 两阶段提交协议&#xff1a;事务管理器分…

如何为客户创建一个简单好用的帮助文档?

产品售后服务难&#xff0c;客服人员压力大&#xff0c;客户不满意。相信这是很多企业都面临的问题&#xff0c;产品是卖出去了&#xff0c;但是做不完的售后&#xff0c;回答不完的重复问题&#xff0c;电话、微信响个不停&#xff0c;售后服务一直都是企业的一个痛点&#xf…

JSR303数据校验和@ControllerAdvice统一异常处理

1.引入依赖&#xff08;springboot2.3之后需要引入&#xff09; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>2.6.6</version> </dependency>…

scrapy总结

一、scrapy是什么&#xff1f;*结构性数据&#xff1a;即同一类型的数据如&#xff1a;某一网页上的同一类型的标签二、scrapy安装pip install scrapy出错提示to update pip&#xff0c;请升级pippython -m pip install --upgrade pip三、scrapy的基本使用&#xff08;爬虫项目…

Python __del__()方法:销毁对象

Python 通过调用 __init__() 方法构造当前类的实例化对象&#xff0c;而本节要学的 __del__() 方法&#xff0c;功能正好和 __init__() 相反&#xff0c;其用来销毁实例化对象。事实上在编写程序时&#xff0c;如果之前创建的类实例化对象后续不再使用&#xff0c;最好在适当位…

Python爬虫-某懂车平台之汽车销量排行榜

前言 本文是该专栏的第33篇,后面会持续分享python爬虫干货知识,记得关注。 之前笔者在本专栏有详细介绍过该平台二手车数据,感兴趣的同学可以在本专栏往前翻阅查找。而本文要介绍的内容,是汽车销量排行数据。 地址:aHR0cHM6Ly93d3cuZG9uZ2NoZWRpLmNvbS9zYWxlcw== (注:地…

哪个牌子台灯对孩子视力好?精选不同价位的学生护眼台灯

在我国&#xff0c;由于科技水平的提高和电子产品的普及&#xff0c;儿童青少年的近视率正逐年攀升&#xff0c;且出现低龄化现象。2020年&#xff0c;我国儿童青少年总体近视率竟高达52.7%&#xff0c;其中6岁儿童已达14.3%&#xff0c;小学生为35.6%&#xff0c;初中生为71.1…

Hue(1): Apache Hue 介绍

1 Hue 是什么 HUEHadoop User Experience Hue 是一个开源的 Apache Hadoop UI 系统&#xff0c;由 Cloudera Desktop 演化而来&#xff0c;最后 Cloudera 公司将其贡献给 Apache 基金会的 Hadoop 社区&#xff0c;它是基于Python Web 框架 Django 实现的。 通过使用 Hue&am…

GAMES101笔记:BRDF和渲染方程

BRDF : 双向反射分布函数(Bidirectional Reflectance Distribution Function) 描述从某个方向入射的能量反射到不同的方向上的能量的分布。 理解反射 从能量的角度理解反射。上图中&#xff0c;ωi\omega_iωi​方向入射的光线具有的Radiance&#xff0c;累积在微小面积dAdAd…

沉浸式 3D 场景下的多视点视频 增强算法研究

沉浸式 3D 场景下的多视点视频 增强算法研究研究内容图像质量增强为什么进行图像质量增强图像有损压缩技术多视点视频中的深度图像特点视点数目增强虚拟视点合成技术视点外推为什么进行视点数目增强主要贡献基于自适应残差网络的多视点压缩深度图像增强算法基于多约束编解码网络…

SautinSoft PDF Focus .Net 8.6.1 Crack

PDF Focus .Net 完整的 API 可在 .NET 平台上转换任何 PDF 文档, .Net 程序集提供 API 以将 PDF 转换为所有格式&#xff1a;DOCX、RTF、HTML、XML、文本、Excel、.Net 和 C# 中的图像。 介绍 PDF Focus .Net 旨在帮助您开发需要转换任何 PDF 文档的应用程序。看看PDF Focus .N…

2023年“华数杯”国际大学生数学建模A题完整思路

2023华数杯如期开赛&#xff0c;本次比赛作为美赛的模拟赛&#xff0c;赛题和比赛时间都和美赛高度相似&#xff0c;因此大家 完全可以当作一次美赛之前的练习赛进行。美赛的发题时间与华数杯一致&#xff0c;都是早晨六点&#xff0c;现已经将机器翻译的初步翻译 结果进行了分…

C#里最简单向文件追加文本的方法AppendAllText

C#里最简单向文件追加文本的方法AppendAllText 在开发的过程中,经常会碰到这样的问题,就是当一个文件没有创建时,就需要创建。但是文件已经创建了,就直接追加数据。 比如我们开发一个记录每天温度的软件, 每天都在固定的时间去记录一下这个温度,那么就需要在这个文件后面…

【第一章】SQL基础知识

目录 ​编辑 1. 认识SQL 1.1 SQL的标准 1.2 SQL的种类 1.3 SQL的功能 2. 常量 2.1 数字常量 2.2 字符串常量 2.3 日期和时间常量 2.4 符号常量 3. 变量 3.1 局部变量 3.2 全局变量 4. 运算符 4.1 算术运算符 4.2 比较运算符 4.3 逻辑运算符 4.4 按位运算符 …