排序1——C语言

排序

  • 1. 复杂度
  • 2. 插入排序
    • 2.1 直接插入排序
    • 2.2 希尔排序
  • 3. 选择排序
    • 3.1 直接选择排序
    • 3.2 堆排序

排序在生活中很常见,比如在网购时,按价格排序,按好评数排序,点餐时,按评分排序等等。而排序有快和慢,快的排序效率高,慢的排序效率低,需要的时间也多。下面就一一介绍各种排序。介绍排序算法时,统一以 升序为例。

1. 复杂度

当一个算法编写完成后,运行时需要消耗时间和空间资源。因此,衡量一个算法的好坏,需要从时间和空间两个维度来衡量,即时间复杂度和空间复杂度。

时间复杂度是衡量快慢的,空间复杂度是衡量该算法运行所需的额外空间。现如今,计算机的内存空间已经很大了,因此空间复杂度已经不是特别关注了。

时间复杂度是一个函数,一个算法的基本操作的执行次数就是该算法的时间复杂度。

void Func1(int N)
{int count = 0;for (int i = 0; i < N; ++i){for (int j = 0; j < N; ++j){++count;}}
}

比如这段代码主要执行的是++count语句,计算该语句的执行次数。

可以看到,++count外套了两层循环,外循环每执行一次,内循环执行N次,而外循环执行了N次,因此++count语句执行了N^2次。算法的执行次数最多的语句一般在循环内部。因此计算时间复杂度,首要计算的就是循环内的。而这个函数可能是若干多项式的和,我们不可能把这个算法的时间复杂度算的非常清楚,只需要知道大概就可以了。因此时间复杂度采用大O渐进表示法

大O渐进表示法:
1.在这个运行次数的函数中,只保留最高阶的那一项,比如10N^2+2N+2---->10N^2
2.如果最高阶存在并且不是1,那么将该项的系数化为1,比如10N^2 —>N^2

最终我们就得到了一个很简单的函数。此外,有些算法的时间复杂度在不同情况下会有不同,因此需要计算最坏情况和最好情况,有些排序算法就存在这种情况。

空间复杂度也是一个函数,是对一个算法在运行过程中临时占用存储空间大小的量度 。
空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。空间复杂度计算的是额外使用的空间的大小,不包括本身对变量开辟的空间。

复杂度主要有以下几种
在这里插入图片描述

其中含有对数的主要是以2为底数的。

2. 插入排序

2.1 直接插入排序

思想:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

什么意思呢?我们举一个例子,比如将排序5,9,7,6,2
排序过程如下。
在这里插入图片描述
当数组遍历完,得到的就是有序的数组了。

void InsertSort(int* array, int numsArr)//待排序数组和数组大小
{//插入numsArr-1次for (int i = 0; i < numsArr - 1; i++){int end = i;int tmp = array[end + 1];while (end >= 0){//后移if (array[end] > tmp){array[end + 1] = array[end];--end;}else{break;}}array[end + 1] = tmp;}
}

直接插入排序的时间复杂度分最好情况和最坏情况,最好情况是数组本就有序,不需要插入,但是需要遍历一遍数组,所以时间复杂度为O(N);最坏情况是数组逆序,插入的次数是1,2,3,4…N-3,N-2,N-1次,数据是一个等差数列,计算出来为**(N^2-N)/2** 根据大O渐进表示法最终化简为O(N^2);

结论:最坏情况O(N^2)最好情况O(N)
空间复杂度O(1),表示没有用到额外空间。

2.2 希尔排序

希尔排序又称为缩小增量排序,希尔排序对直接插入排序进行了优化,先进行若干次预排序,在进行一次直接插入排序,预排的作用是使得所有记录更快的接近有序。

基本思想是:先选定一个整数(假设为K),把待排序的所有记录分成K个
,所有距离为K的记录分在同一组内,并对每一组内的记录进行插入排序。然后缩小K的值,重复上述分组和排序的工作。当K=1时,所有记录在一组内排好序。

这里举例将10,9,8,7,6,5,4,3,2,1进行第一轮的排序,假设K=3;
排序过程如图
在这里插入图片描述
可以看到,第一轮的排序结果,已经很接近有序了,缩小K的值,在进行分组和排序,当K=1时,所有数据为一组,此时进行的就是直接插入排序。

将数据分组进行预排,可以将更小的数据更快的插入到前面更大的数据更快的移到后面,减少了插入和移动的次数。

整数的选择也是一个问题,太小了会导致预排效果不明显,太大了会导致预排次数变多,因此整数的每次选取方式为缩小三倍在加1,加1会使得最后一次这个整数一定为1。即最后一次的排序一定是直接插入排序。

代码如下

void ShellSort(int* array, int numsArr)
{int gap = numsArr;while (gap > 1){//间隔gap的数据作为一组,一共gap组//gap=1时是直接插入排序gap = gap / 3 + 1;    for (int i = 0; i < numsArr - gap; i++){int end = i;int tmp = array[end + gap];while (end >= 0){//往后挪数据if (array[end] > tmp){array[end + gap] = array[end];end -= gap;}else{break;}}array[end + gap] = tmp;}}
}

希尔排序的时间复杂度比较难算,因为预排和gap的选择会影响结果,并且每一次的预排都会对下一次的预排产生影响。这里直接说结论,希尔排序的时间复杂度大约为N^1.3。

3. 选择排序

3.1 直接选择排序

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

这里进行一个小的优化,同时选出最大和最小的元素,分别放到末尾和起始位置。

但也会产生一个小问题,我们先看代码。

void SelectSort(int* array, int numsArr)
{int begin = 0, end = numsArr - 1;while (begin < end){//最大最小值的下标int minIndex = begin, maxIndex = begin;for (int i = begin + 1; i <= end; i++){//找最小值并更新下标if (array[i] < array[minIndex]){minIndex = i;}//找最大值并更新下标if (array[i] > array[maxIndex]){maxIndex = i;}}swap(&array[begin], &array[minIndex]);//最大值和起始位置重复了if (maxIndex == begin)maxIndex = minIndex;swap(&array[end], &array[maxIndex]);begin++;end--;}
}

问题是会产生数据重复,看下面这组数据。
9,2,3,4,5,6,8,1
如果没有这两条语句会产生什么情况。

if (maxIndex == begin)
maxIndex = minIndex;

在这里插入图片描述
当最大值的下标和起始位置的下标重复,就会产生上面的情况,解决办法就是加上判断语句。

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

3.2 堆排序

关于堆排序在之前已经介绍过了,这里就不在赘述了,大家可以看这篇进行了解:堆的应用
代码如下

void HeapSort(int* array, int numsArr)
{//向下调整建堆,复杂度O(N)for (int i = (numsArr - 2) / 2; i >= 0; i--){AdJustDown(array, numsArr, i);}//升序建大堆;降序建小堆//复杂度O(N*logN)int i = numsArr - 1;while (i > 0){swap(&array[0], &array[i]);//交换首尾元素AdJustDown(array, i, 0);i--;}
}
void AdJustDown(int* array, int num_array, int parent)//建大堆
{//假设左孩子符合条件int child = parent * 2 + 1;while (child < num_array){//存在右孩子且右孩子符合条件if (child + 1 < num_array && array[child + 1] > array[child]){++child;}if (array[child] > array[parent]){//交换数据swap(&array[child], &array[parent]);//更新下标parent = child;child = parent * 2 + 1;}else{break;}}
}

这里对堆排序的时间复杂度进行一个计算。
如下图,这是建堆的时间复杂度

在这里插入图片描述
根据大O渐进表示法,最终建堆的时间复杂度为O(N)

而进行排序时,时间复杂度为
在这里插入图片描述
建堆的时间复杂度为O(N),排序的时间复杂度为O(NlogN),最大项为NlogN,因此堆排序的时间复杂度为O(N*logN)

关于其他排序,后续会依次介绍。

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

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

相关文章

「JS 基础」迭代器和生成器 Iterator Generator 入门

前言 JavaScript的生成器(Generators)和迭代器(Iterators)是ES6引入的功能,使得开发者可以更方便地实现自定义的迭代逻辑。 迭代器 迭代器是一种接口,它为各种不同的数据结构(如数组或者映射)定义了一个标准的遍历方法。具体来说,一个迭代器对象必须实现一个 next…

电源监视继电器HRTH-J-2H2D AC220V 导轨安装 JOSEF约瑟

系列型号&#xff1a; HRTH-Y-2H2D-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-Y-2Z-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-Y-2H-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-J-2H2D-X-T跳位监视、合位监视、电源监控继电器…

分布式事务方案与Seata详解

分布式事务与Seata详解 一、分布式事务1.什么是分布式事务2.分布式事务解决方案-2PC3.分布式事务解决方案-3PC4.分布式事务解决方案-TCC5.分布式事务解决方案-XA6.可靠消息最终一致性6.1 本地消息表6.2 事务消息 7.最大努力通知8.SAGA9.分布式事务解决方案思考 二、Seata 简介与…

[leetcode] 427. 建立四叉树

给你一个 n * n 矩阵 grid &#xff0c;矩阵由若干 0 和 1 组成。请你用四叉树表示该矩阵 grid 。 你需要返回能表示矩阵 grid 的 四叉树 的根结点。 四叉树数据结构中&#xff0c;每个内部节点只有四个子节点。此外&#xff0c;每个节点都有两个属性&#xff1a; val&#x…

30万的源码和300的源码有什么区别?

源码的质量很大程度上取决于其来源、开发者的技术水平和项目的具体需求。有些源码可能确实存在一些问题&#xff0c;比如代码结构混乱、注释不清晰、性能不佳等。 而价高优秀的源码都采用了高效的数据结构和算法&#xff0c;代码结构清晰&#xff0c;逻辑严谨&#xff0c;具有良…

2024最方便申请SSL证书方法介绍

申请SSL证书其实就像你去官方机构办个身份证&#xff0c;证明你的网站是合法且安全的。这里给你白话一点的简单步骤&#xff1a; 步骤一&#xff1a;确定需求 1. 域名&#xff1a;确保你有一个要申请证书的域名&#xff0c;就是你的网站地址&#xff0c;比如 www.example.com。…

本地知识库搭建教程来了,跟着做就行

你是不是常常因为找不到几个月前那个重要的工作笔记而头疼&#xff1f;或者是厌倦了反复在互联网的海洋中搜寻相同的信息&#xff1f;一个本地的知识库可能是你需要的解决方案。今天&#xff0c;我就要为你分享如何简单地搭建起自己的知识库&#xff0c;让你的信息更有组织、更…

.NET8 上的 Bing :动态PGO的影响

自从我上次更新大家有关.NET在Bing技术栈中的状态以来已经过去了一年多&#xff0c;尤其是位于核心位置的高性能工作流执行引擎。在这段时间里&#xff0c;这个引擎的应用范围只增不减&#xff0c;特别是随着Microsoft Copilot的发布。虽然我们的工作流引擎起源于Bing&#xff…

Harmony鸿蒙南向外设驱动开发-Pin_auth

功能简介 口令认证是端侧设备不可或缺的一部分&#xff0c;为设备提供一种用户认证能力&#xff0c;可应用于设备解锁、支付、应用登录等身份认证场景。用户注册口令后&#xff0c;口令认证模块就可为设备提供密码解锁的功能&#xff0c;保证设备的安全使用。口令识别的整体架…

【Python使用】python高级进阶知识md总结第8篇:TCP 网络应用程序开发流程,1. TCP 网络应用程序开发流程的介绍【附代码文档】

python高级进阶全知识知识笔记总结完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;操作系统&#xff0c;虚拟机软件。ls命令选项&#xff0c;mkdir和rm命令选项。压缩和解压缩命令&#xff0c;文件权限命令。编辑器 vim&#xff0c;软件安装。获取进程编号…

Solana 上创建自己的 SLPToken:简明指南

Solana 定义 Solana 是由 Solana Labs 创建的区块链平台&#xff0c;旨在提供高吞吐量和低延迟的去中心化应用&#xff08;DApps&#xff09;开发环境。它采用一系列创新技术&#xff0c;如 PoH&#xff08;Proof of History&#xff09;共识机制和 Tower BFT&#xff08;BFT …

APIGateway的认证

APIGateway的支持的认证如下&#xff1a; 我们从表格中可以看到&#xff0c;HTTP API 不支持资源策略的功能&#xff0c;另外是通过JWT的方式集成Cognito的。 对于REST API则是没有显示说明支持JWT认证&#xff0c;这个我们可以通过Lambda 自定义的方式来实现。 所以按照这个…