【数据结构和算法】--- 基于c语言排序算法的实现(1)

目录

  • 一、排序的概念及其应用
    • 1.1排序的概念
    • 1.2 排序的应用
    • 1.3 常见的排序算法
  • 二、插入排序
    • 2.1直接插入排序
    • 2.2 希尔排序
      • 2.2.1 预排序
      • 2.2.2 缩小gap
      • 2.2.3 小结
  • 三、选择排序
    • 3.1 直接选择排序
    • 3.2 堆排序

一、排序的概念及其应用

1.1排序的概念

排序: 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
内部排序: 数据元素全部放在内存中的排序。
外部排序: 数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

1.2 排序的应用

以下是 “软科中国大学排名” 情况,这便是日常生活中排序的应用,此处排序标准为,以各个大学的总分作为唯一标准,进行降序排序。 此处的排序便是由排序算法实现,下面将对不同的排序算法进行剖析。

在这里插入图片描述

1.3 常见的排序算法

在这里插入图片描述
下面将基于c语言,对以上七种排序逐一实现。

二、插入排序

2.1直接插入排序

基本思想:
直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
我们可以将直接插入排序想象成玩扑克牌,即每当我们拿到一张牌,然后插入到我们手上已排好序的牌中,从小到大直到找到合适的位置然后插入,以此循环直到排完序为止。
依据上述方法,我们可以先排数组的前两个数。第一个数作为已排好序的数组,第二个数作为要插入数组的数,插入完成后,将上述所有已插入的数作为已排好序的数组,然后再向后取一个数执行上述逻辑。 以此作为循环的主体,直到取完数组中所有的数,即当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移。

代码实现:

//直接插入排序
void InsertSort(int* a, int n)
{for(int i = 0; i < n - 1; i++){//[0, end] 已排好序的数组int end = i;int tmp = a[end + 1];//要插入的数//tmp 向前比较 -- 小于前一个数,则 a[end] 向后拷贝,end--,继续比较前一个数//大于则说明 tmp 到了合适的位置while(end >= 0){if(tmp <= a[end]){a[end + 1] = a[end];end--;}else{break;}}//比较完成,插入!a[end + 1] = tmp;}
}

代码实现时几点注意

  • 确定好要以排好序的数组范围(下标为0 ~ n - 2)n -1位置是最后一个要插入的数;
  • 要插入的数为已排好序的数组最后一个元素(end = i)的下一个(tmp = a[end + 1),使用tmp记录;
  • tmp向前比较,小于a[end]则继续比较前一个,当前a[end]向后拷贝,并使end--直到tmp大于a[end],或end < 0,则结束,并使a[end] = tmp

直接插入排序动态演示:

在这里插入图片描述

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度: O(N^2)
  3. 空间复杂度: O(1),它是一种稳定的排序算法;
  4. 稳定性: 稳定

2.2 希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

根据元素集合越接近有序,直接插入排序算法的时间效率越高的规律,那么我们可以想方法先把一堆数据排的接近有序(预排序),然后再进行直接插入排序

2.2.1 预排序

可以定义gap来表示每次预排序的元素的跨度(即每次趟排序的数组下标相隔的值),这时gap也表示整个数组要排序的趟数。大致如下图所示:
在这里插入图片描述
gap趟中的每一趟,又是直接插入排序。那么在直接插入排序的基础上,我们只需要控制一下初始值,下标增值和结束条件即可,如:for(int j = i; j < n - gap; j += gap),其中n - gap是因为,每趟排序的最后一个元素都在整个数组的后gap个,又因为直接插入排序最后一个位置不取,所以要< n - gap。代码如下:

//预排序(以 gap = 3 为例)
int gap = 3;
//gap 趟
for(int i = 0; i < gap; i++)
{//直接插入排序for(int j = i; j < n - gap; j += gap){int end = j;int tmp = a[end + gap];while(end >= 0){if(tmp <= a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp; }
}

当然还可以对上面代码进行一点小优化可以将外层两个for循环改成一个:for(int j = 0; j < n - gap; j++) 事实上循环总次数是不变的,我们只是将原来先排好第一组再排后面组的思路,改成了混在一起排,效果还是一样的。由一组一组排变为了多组并排。

2.2.2 缩小gap

有了预排序,那么我们只要合理的控制gap的大小,便完成了希尔排序。如:gap = gap / x + 1其中的x可以根据具体的待排序的数组的长度来决定。 待排序数组长,则x设置较大一些;待排序数组短,则x设置较小一些。gap / x后还要加一,是为了让排序的最后一趟gap = 1,即直接插入排序。

//希尔排序(缩小增量排序)
void ShellSort(int* a, int n)
{int gap = n;//gap > 1 时是预排序,目的是让他接近有序//ga[ = 1 时是直接插入排序,目的是让他有序while(gap > 1){gap = gap / 3 + 1;  //加1是为了让他最后一次 gap = 1//预排序// ....}
}

排序整体逻辑基本如下:
在这里插入图片描述

2.2.3 小结

希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. gap > 1时都是预排序,目的是让数组更接近于有序。如此一来,当gap == 1时,数组已经接近有序的了,这样效率也会很高。这样整体而言,可以达到优化的效果。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定:
    《数据结构(C语言版)》— 严蔚敏
    在这里插入图片描述
    《数据结构-用面相对象方法与C++描述》— 殷人昆
    在这里插入图片描述
    因为咋们的gap是按照 Knuth 提出的方式取值的,而且 Knuth 进行了大量的试验统计,我们暂时就按照:O(N^1.25)O(1.6 * N^1.25)来算。
  4. gap越大,大的值越快跳到后面,小的值越快跳到前面,越不接近有序;gap越小,大的之越慢跳到后面,小的值越慢跳到前面,越接近有序;
  5. 稳定性: 不稳定

三、选择排序

3.1 直接选择排序

基本思想:
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

直接插入排序动态演示:
在这里插入图片描述
上述的方法是从头遍历到尾,找最小值,然后插入到目标位置,事实上效率并不是很高,于是我们可以这样进行点小优化定义一个变量int begin = 0,从下标为begin的位置向后找小,再定义一个变量int end = n - 1,从下标为begin的位置向后找大,待循环结束大值和下标为end的值交换,小值和下标为begin的值交换,然后begin++; end--;,直到begin == end排序结束。这样每次循环都会找到两个目标值,且缩小了下一次搜索的范围,达到了优化的效果。
代码实现:

//直接插入选择(优化)
void SelectSort(int* a, int n)
{int begin = 0, end = n - 1;//记录 较大值 和 较小值 的下标int mini = begin, maxi = degin;while(begin < end){//找大值和小值for(int i = begin + 1; i < end + 1; i++){if(a[i] < a[mini])mini = i;if(a[i] > a[maxi])maxi = i;}//交换Swap(&a[begin], &a[mini]);//判断防止最大值丢失if(maxi == begin)maxi = mini;Swap(&a[end], &a[maxi]);++begin;--end;}
}

还有一点需要注意的是,交换完一个值我们要先判断,看最大值是否在begin位置,if(maxi == begin),若在,则将maxi换到mini位置。逻辑大致如下:
在这里插入图片描述

直接选择排序的特性总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  2. 时间复杂度: O(N^2)
  3. 空间复杂度: O(1)
  4. 稳定性: 不稳定

3.2 堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
因为之前已经介绍过了,所以这里就不多讲了,详细请参考:【数据结构和算法】—二叉树(2)–堆的实现和应用

直接选择排序的特性总结:

  1. 堆排序使用堆来选数,效率就高了很多。
  2. 时间复杂度: O(N*logN)
  3. 空间复杂度: O(1)
  4. 稳定性: 不稳定

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

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

相关文章

RTE2023第九届实时互联网大会:揭秘未来互联网趋势,PPT分享引领行业新思考

随着互联网的不断发展&#xff0c;实时互动技术正逐渐成为新时代的核心驱动力。 在这样的背景下&#xff0c;RTE2023第九届实时互联网大会如期而至&#xff0c;为业界人士提供了一个探讨实时互联网技术、交流创新理念的绝佳平台。 本文将从大会内容、PPT分享价值等方面&#…

ShardingSphere 5.x 系列【6】YAML 配置介绍

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 前言2. YamlConfiguration3. 常用配置项3.1 JDBC 驱动3.2 数据源3.3 规则…

mysq开启慢查询日志,对慢查询进行优化

1.创建实验的环境 创建对应的数据库&#xff0c;然后写脚本向数据库中写入400万条的数据 //创建实验用的数据库 CREATE DATABASE jsschool;//使用当前数据库 USE jsschool;//创建学生表 CREATE TABLE student (sno VARCHAR(20) PRIMARY KEY COMMENT 学生编号,sname VARCHAR(20…

加固平板电脑丨三防智能平板丨工业加固平板丨智能城市管理

随着智能城市的不断发展&#xff0c;人们对于城市管理的要求也在不断提高&#xff0c;这就需要高效、智能的城市管理平台来实现。而三防平板就是一款可以满足这一需求的智能设备。 三防平板是一种集防水、防尘、防摔于一体的智能平板电脑&#xff0c;它可以在复杂的环境下稳定运…

python介绍,安装Cpython解释器,IDE工具pycharm的使用

python介绍 官方的Python解释器本质是基于C语言开发的一个软件&#xff0c;该软件的功能就是读取以py.结尾的文件内容&#xff0c;然后按照Guido定义好的语法和规则去翻译并执行相应的代码。这种C实现的解释器被称为Cpython。 python解释器的种类&#xff1a;Jython IPyth…

记录下ibus-libpinyin输入法的重新安装

目前的版本为&#xff1a; 首先把现在的ibus-libpinyin卸了 sudo apt-get --purge remove ibus-libpinyin sudo apt-get autoremove 安装教程请参考 Installation libpinyin/ibus-libpinyin Wiki GitHub yilai sudo apt install pkg-config sudo apt-get install lib…

实战分享:SpringBoot在创新创业项目管理中的应用

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Unity3d Shader篇(三)— 片元半兰伯特着色器解析

文章目录 前言一、片元半兰伯特着色器是什么&#xff1f;1. 片元漫反射着色器的工作原理2. 片元半兰伯特着色器的优缺点优点&#xff1a;缺点&#xff1a; 3. 公式 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数…

QT设置qss

Qt设置qss文件&#xff08;设置在qrc中&#xff09; 1、右击项目选择添加新文件 2、在弹出的对话框中选择Qt -> Qt Resource File 3、随便起一个名称 4、在代码路径下新建一个stylesheet.qss文件&#xff0c;随便写入一些样式 5、右击resources.qrc&#xff0c;选择添加…

地理格网地址赋码过程

1.地址地名赋码流程 1.由镇街收集数据并且统一入库到地址数据库中; 2.进行地址字段的详细校验; 3.对进行校验通过的数据按照西湖区统一地址规则进行赋码 4.对进行校验失败的数据反馈成 execl 给镇街进行数据的核对校对 2地址校验规则 # 必填字段规范 省(字段名 - provinc…

进阶C语言-通讯录的实现

通讯录 🎈1.设计要求🎈2.程序实现🔭2.1打印菜单及初始化通讯录🔭2.2显示所有联系人🔭2.3查找指定的联系人🔭2.4删除指定的联系人🔭2.5查找指定的联系人🔭2.6修改指定联系人🔭2.7按照年龄排序(以此为例)🎈3.全部源码以及实现🎈1.设计要求 🌞通过前面…

SpringSecurity(17)——OAuth2令牌管理策略

刷新令牌策略 注意&#xff1a;刷新令牌只有在授权码模式和密码模式中才有&#xff0c;对应的指定这两种模式时&#xff0c;在类型上加上refresh_token <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-se…

【Flink入门修炼】1-1 为什么要学习 Flink?

流处理和批处理是什么&#xff1f; 什么是 Flink&#xff1f; 为什么要学习 Flink&#xff1f; Flink 有什么特点&#xff0c;能做什么&#xff1f; 本文将为你解答以上问题。 一、批处理和流处理 早些年&#xff0c;大数据处理还主要为批处理&#xff0c;一般按天或小时定时处…

如何在docker中访问电脑上的GPU?如何在docker中使用GPU进行模型训练或者加载调用?

如何在docker中访问电脑上的GPU&#xff1f;如何在docker中使用GPU进行模型训练或者加载调用&#xff1f; 其实使用非常简单&#xff0c;只是一行命令的事&#xff0c;最主要的事配置好驱动和权限。 docker run -it --rm --gpus all ycj520/centos:1.0.0 nvidia-smi先看看 st…

Kafka 使用手册

kafka3.0 文章目录 kafka3.01. 什么是kafka&#xff1f;2. kafka基础架构3. kafka集群搭建4. kafka命令行操作主题命令行【topic】生产者命令行【producer】消费者命令行【consumer】 5. kafka生产者生产者消息发送流程Producer 发送原理普通的异步发送带回调函数的异步发送同步…

Mac OS中创建适合网络备份的加密镜像文件:详细步骤与参数选择

这篇文章提供了在Mac OS中创建适合网络备份的加密镜像文件的详细步骤&#xff0c;同时探讨了在选择相关参数时的关键考虑因素&#xff0c;以确保用户能够安全、高效地存储和保护重要数据。 创建步骤 在Mac OS Monterey中&#xff0c;你可以使用“磁盘工具”&#xff08;Disk …

【C++】初始化列表--再谈构造函数

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

PXI-1 Peripheral Module 64Bit 改混合槽 PXI Express Hybrid Slot

PXI PXIEPXI_LBR05VauxPXI_LBR2WAKE#PXI_LBR3ALERT#PXI_LBR412VPXI_LBR512VPXI_LBRL0/PXI_STAR0GNDPXI_LBRL1/PXI_STAR1GNDPXI_LBRL2/PXI_STAR2GNDPXI_LBRL3/PXI_STAR33.3VPXI_LBRL4/PXI_STAR43.3VPXI_LBRL5/PXI_STAR53.3V 实际就是拆掉这个 红黄框里的端子。。

UE4 C++ 动态加载类和资源

动态加载类和资源&#xff1a;指在运行时加载 .cpp void AMyActor::BeginPlay() {Super::BeginPlay();//动态加载资源UStaticMesh* MyTempStaticMesh LoadObject<UStaticMesh>(nullptr,TEXT("/Script/Engine.StaticMesh/Game/StarterContent/Shapes/Shape_NarrowC…

Android9~Android13 某些容量SD卡被格式化为内部存储时容量显示错误问题的研究与解决方案

声明:原创文章,禁止转载! Android9~Android13 某些容量SD卡被格式化为内部存储时容量显示错误问题的研究与解决方案 分析Android11 系统对于EMMC/UFS作为内部存储、SD卡被格式化为内部存储、SD卡/U盘被格式化为便携式存储的不同处理 一.现象描述 实测Android9 Android10 A…