当前位置: 首页 > news >正文

几种内部排序算法的cpp代码实现与分析

零、测试函数

typedef void (*SortFunc) (int*&, int);inline void swap(int &a, int &b) {int tmp = a;a = b;b = tmp;
}inline void printArr(int* a, int n) {for (int k = 0; k < n; ++k) {std::cout << a[k] << ' ';}std::cout << std::endl;
}void testSort(SortFunc func) {srand(time(nullptr));int n = rand() % 10 + 10;int* a = new int[n];for (int i = 0; i < n; ++i) {a[i] = rand() % 100;}printArr(a, n);(*func)(a, n);printArr(a, n);}

首先使用typedef将传参为(int*&, int),返回值为空的指向函数的指针类型命名为SortFunc。

其次,定义swap函数与printArr函数,swap函数会在冒泡排序、快速排序等排序算法中使用,而printArr用来输出数组。

最后,定义函数testSort,传参一个指向函数的指针,在函数体内,程序将生成一个长度取10~20之间的随机值,元素大小取0~100之间的随机值的一个数组。先对数组进行一次输出,然后调用参数func指向的函数对数组进行排序,再排序结果输出一次。

一、插入排序

插入排序的思想是每次都将一个待排序的元素按关键字大小插入前面已排序好的子序列。插入排序主要分为:直接插入排序、折半插入排序、希尔排序。

在数组已基本有序的前提下,插入排序效率最高。

1. 直接插入排序

void straightInsertionSort(int* &a, int n) {for (int i = 1; i < n; ++i) {if (a[i] >= a[i-1]) continue;int j;int tmp = a[i];for (j = i - 1; tmp < a[j] && j >= 0; --j) {a[j+1] = a[j];}a[j+1] = tmp;printArr(a, n);}}

空间复杂度:O(1)
时间复杂度:最好情况下为O(n),即数组已有序,只需进行一次遍历、最坏情况下为O(n2)、平均O(n2)
稳定性:具有稳定性

2. 折半插入排序

void binaryInsertionSort(int* &a, int n) {for (int i = 1; i < n; ++i) {if (a[i] >= a[i-1]) continue;int tmp = a[i];int low = 0;int high = i-1;int mid;while (low <= high) {mid = (low + high) / 2;if (a[mid] > tmp) {high = mid - 1;} else {low = mid + 1;}}for (int j = i; j > high+1; --j) {a[j] = a[j-1];}a[high+1] = tmp;printArr(a, n);}}

空间复杂度:O(1)
时间复杂度:最好情况下为O(n),即数组已有序,只需进行一次遍历、最坏情况下为O(n2)、平均O(nn)
稳定性:具有稳定性

3. 希尔排序

void shellSort(int* &a, int n) {int gap = n >> 1;int tmp, j;while (gap) {std::cout << "gap = " << gap << std::endl;for (int i = gap; i < n; ++i) {if (a[i] >= a[i-gap]) continue;tmp = a[i];for (j = i-gap; tmp < a[j] && j >= 0; j -= gap) {a[j+gap] = a[j];}a[j+gap] = tmp;printArr(a, n);}gap >>= 1;}}

空间复杂度:O(1)
时间复杂度:当n在某个特定范围内时,希尔排序的时间复杂度均为O(n1.3)。在最坏情况下希尔排序的时间复杂度为O(n2)。
稳定性:不具有稳定性
注意希尔排序仅适用于顺序存储的线性表

二、交换排序

1. 冒泡排序

void bubbleSort(int* &a, int n) {for (int i = 0; i < n - 1; ++i) {bool flag = true;for (int j = n - 1; j > i; --j) {if (a[j - 1] > a[j]) {swap(a[j-1], a[j]);flag = false;}}printArr(a, n);if (flag) {break;}}}

空间复杂度:O(1)
时间复杂度:最好情况下为O(n),即数组已有序,只需进行一次遍历、最坏情况下为O(n2)、平均O(n2)
稳定性:具有稳定性

2. 快速排序

void quickSort(int* &a, int high, int low = 0) {int i = low;int j = high - 1;if (i >= j) return;int pivot = a[i];while (i < j) {while (i < j && pivot < a[j]) j--;a[i] = a[j];while (i < j && a[i] < pivot) i++;a[j] = a[i];}a[i] = pivot;std::cout << "pivot = " << pivot << std::endl;quickSort(a, i, low);quickSort(a, high, i + 1);}

空间复杂度:由于快速排序是递归的,需要借助一个递归的工作栈来保存每层递归的必要信息,其容量与递归调用的最大深度保持一致。最好情况下为O(log2n);最坏情况下,即数组已有序,需要进行n-1次递归调用,空间复杂度为O(n)。平均空间复杂度为O(log2n)。

时间复杂度:最好情况下为O(nlog2n),最坏情况下为O(n2),平均为O(nlog2n)。

稳定性:不具有稳定性。

在大多数情况下,快速排序是平均性能最高的排序算法,但是排序算法并不适合对已基本接近有序的数组进行排序。

三、选择排序

1. 简单选择排序

void selectionSort(int* &a, int n) {int minIndex;for (int i = 0; i < n - 1; i++) {minIndex = i;for (int j = i + 1; j < n; j++) {if (a[j] < a[minIndex]) {minIndex = j;}}if (minIndex != i) {swap(a[i], a[minIndex]);}printArr(a, n);}}

空间复杂度:O(1)
时间复杂度:最好情况、最坏情况、平均情况下都为O(n2)
稳定性:不具有稳定性

2. 堆排序

void heapAdjust(int* &heap, int root, int n) {int tmp = heap[root]; // 暂存根节点for (int i = 2 * root + 1; i < n; i = i * 2 + 1) {if (i + 1 < n && heap[i] < heap[i+1]) {i++; // 如果右子结点更大,让指针对准右子结点}if (tmp >= heap[i]) {break;} else {heap[root] = heap[i];root = i;}}heap[root] = tmp;}void buildMaxHeap(int* &heap, int n) {for (int i = n / 2 - 1; i >= 0; --i) {heapAdjust(heap, i, n);}
}void heapSort(int* &a, int n) {buildMaxHeap(a, n);for (int i = n - 1; i > 0; --i) {swap(a[i], a[0]);heapAdjust(a, 0, i - 1);}
}

空间复杂度:O(1)
时间复杂度:建堆的时间复杂度为O(n),之后有n-1次向下调整,每次向下调整复杂度为O(h),h为堆的深度,约为log2n,故最好情况、最坏情况、平均情况下时间复杂度都为O(nlog2n)
稳定性:不具有稳定性

四、归并排序

static int* b;void merge(int* &a, int low, int mid, int high) {for (int i = low; i <= high; ++i) {b[i] = a[i];}int i, j, k;for (i = low, j = mid + 1, k = low; i <= mid && j <= high; k++) {if (b[i] <= b[j]) {a[k] = b[i++];} else {a[k] = b[j++];}}while (i <= mid) {a[k++] = b[i++];}while (j <= high) {a[k++] = b[j++];}}void mergeSort(int* &a, int low, int high) {if (low >= high) return;int mid = (low + high) / 2;mergeSort(a, low, mid);mergeSort(a, mid + 1, high);merge(a, low, mid, high);
}void mergeSort(int* &a, int n) {b = new int[n];mergeSort(a, 0, n-1);
}

空间复杂度:由于数组b的创建,空间复杂度为O(n)
时间复杂度:每趟归并复杂度为O(n)一共需要log2n次归并,所以复杂度为O(nlog2n)。
稳定性:具有稳定性。

五、基数排序

class ListNode {public:int data;ListNode* next;friend std::ostream & operator<< (std::ostream &out, ListNode &l) {ListNode* p = l.next;while(p) {out << p->data << ' ';p = p->next;}return out;}};void radixSort(ListNode* l, int d) {ListNode *p, *q;for (int i = 0; i < d; ++i) {ListNode* start[16];ListNode* end[16];bool flags[16];for (bool &flag : flags) {flag = false;}while (l->next) {p = l->next;l->next = p->next;p->next = nullptr;int x = p->data;int index = (x >> (4 * i)) & 0xf;if (flags[index]) {end[index]->next = p;end[index] = p;} else {start[index] = p;end[index] = p;flags[index] = true;}}q = l;for (int j = 0; j < 16; ++j) {if (flags[j]) {q->next = start[j];q = end[j];}}std::cout << *l << std::endl;}}

设r个队头指针队尾指针(上述代码中是16个),共进行d趟分配与收集。

空间复杂度:O®

时间复杂度:进行d趟分配与收集,一趟分配O(n),一趟收集O(r),时间复杂度为O(d(n+r))

稳定性:具有稳定性

六、总结

  1. 若n较小,可采用直接插入排序或简单选择排序。直接插入排序比较次数少移动次数多,简单选择排序比较次数多移动次数少。所以当记录的信息量较大时,更适合选用简单选择排序。
  2. 若文件初始状态已基本有序,应当使用直接插入排序或冒泡排序。
  3. 若n较大,则应该使用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序,目前快速排序被认为是所有基于比较的排序算法中最好的算法,当待排序关键字随机分布时,快速排序所使用的平均时间最短。堆排序相比快速排序的优点是:不需要开辟额外的内存空间。但这两种算法都是不稳定的排序算法。并且当数据已基本有序时,快速排序效率较低,不宜使用。
  4. 若n很大,而记录的关键字位数比较少且可分解,宜采用基数排序。
  5. 当记录信息量较大,为避免耗费大量时间移动记录,可使用链表作为存储结构。

相关文章:

几种内部排序算法的cpp代码实现与分析

零、测试函数 typedef void (*SortFunc) (int*&, int);inline void swap(int &a, int &b) {int tmp a;a b;b tmp; }inline void printArr(int* a, int n) {for (int k 0; k < n; k) {std::cout << a[k] << ;}std::cout << std::endl; }…...

第3天学习Docker-Docker部署常见应用(MySQL、Tomcat、Nginx、Redis、Centos)

前提须知&#xff1a; &#xff08;1&#xff09;搜索镜像命令 格式&#xff1a;docker search 镜像名 &#xff08;2&#xff09;设置Docker镜像加速器 详见文章&#xff1a;Docker设置ustc的镜像源&#xff08;镜像加速器&#xff09; 1、部署MySQL 拉取镜像&#xff08;这…...

给大家介绍四款最受欢迎的抓包神器

身为互联网人&#xff0c;无论在平时开发还是在测试过程中&#xff0c;我们都不可避免的会涉及到网络安全性&#xff0c;如何监测网络请求&#xff0c;从而最大程度的保证数据的安全&#xff0c;需要我们了解并掌握抓包的技巧。那么何谓抓包呢&#xff1f;抓包就是将网络传输发…...

解决Reids过期方案 游标遍历清除Redis过期的key

游标遍历清除Redis过期的key 为什么要清除Redis过期的Key ​ Redis的过期清理是一种懒惰的清理方案&#xff0c;他不会过期后立刻清除&#xff0c;而是在Key被访问的时候进行删除&#xff0c;Redis这么做的目的就是为了提高性能降低资源开销。 ​ 具体来说&#xff0c;一个K…...

K8s基础10——数据卷、PV和PVC、StorageClass动态补给、StatefulSet控制器

文章目录 一、数据卷类型1.1 临时数据卷&#xff08;节点挂载&#xff09;1.2 节点数据卷&#xff08;节点挂载&#xff09;1.3 网络数据卷NFS1.3.1 效果测试 1.4 持久数据卷&#xff08;PVC/PV&#xff09;1.4.1 效果测试1.4.2 测试结论 二、PV、PVC生命周期2.1 各阶段工作原理…...

oracle系统查询~3

查看实例的基本信息 SQL> col host_name for a25 col instance_name for a15 col version for a15 col status for a10 set linesize 600 col host_name for a20 select instance_number,instance_name,host_name,version,startup_time,status,archiver f…...

Mybatis源码(九)— chche

Mybatis中共有三级缓存&#xff0c;其中一级缓存默认开启&#xff0c;作用范围是在sqlSession对象&#xff08;同一个会话&#xff09;&#xff0c;二级缓存需要手动配置开启&#xff0c;作用范围是在sqlSessionFactory对象下的同一个namespace范围&#xff08;所以二级缓存是可…...

回溯法--N皇后问题

N皇后问题 一、问题描述二、示例2.1 四皇后的2个可行解2.2 过程图示 三、问题分析3.1涉及到的概念递归回溯 3.2 分析 四、 代码实现4.1 实现思路宏观&#xff1a;微观&#xff1a; 4.2 递归函数NS图4.3 代码 一、问题描述 1、按照国际象棋的规则&#xff0c;皇后可以攻击与之处…...

ajax请求

ajax的优点 可以无需刷新页面而与服务器进行通信允许你根据用户事件来更新部分页面内容 ajax的缺点 没有浏览历史&#xff0c;不能回退存在跨域问题SEO不友好 get请求 <button>点击发送请求</button><div id"result"></div><script>…...

K8S系列之污点和容忍度详细分析

架构图 本篇文档主要介绍污点和容忍度的关系。 污点和容忍度 污点顾名思义就是脏的东西&#xff0c;给节点添加污点来限制pod调度到该节点上&#xff0c;如果pod可以容忍这种污点就可以被调度到有污点的节点上&#xff0c;如果不能容忍就不能被调度到该节点上。 污点作用于节…...

【算法】Minimum Moves to Move a Box to Their Target Location 推箱子

文章目录 Minimum Moves to Move a Box to Their Target Location 推箱子问题描述&#xff1a;分析代码 Tag Minimum Moves to Move a Box to Their Target Location 推箱子 问题描述&#xff1a; 问题 「推箱子」是一款风靡全球的益智小游戏&#xff0c;玩家需要将箱子推到仓…...

决策引擎平台建设方案

文档修订历史 时间版本主要内容2023.05.12v1.0.0初始化 1. 概述 1.1 需求 1.1.1 需求背景 当同一个业务场景中&#xff0c;有非常多的业务分支后&#xff0c;需要有非常多的 if 判断&#xff0c;来承载这些简单的业务逻辑&#xff0c;但随着业务的发展&#xff0c;业务逐渐…...

SpringBoot Starter 作用及原理

本文会以 mybatis 为例&#xff0c;通过对比 mybatis-spring 和 mybatis-spring-boot-starter 代码示例&#xff0c;了解 Starter 的作用。并对 mybatis-spring-boot-starter 进行简单剖析&#xff0c;了解 Starter 原理。 下面还有投票&#xff0c;一起参与进来吧&#x1f44d…...

【rust】| 05——语法基础 | 流程控制

系列文章目录 【rust】| 00——开发环境搭建 【rust】| 01——编译并运行第一个rust程序 【rust】| 02——语法基础 | 变量(不可变?)和常量 【rust】| 03——语法基础 | 数据类型 【rust】| 04——语法基础 | 函数 【rust】| 05——语法基础 | 流程控制 文章目录 流程控制1. 条…...

解决Makefile: recipe for target ‘xxx‘ failed

author daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 问题 在android编译Kernel调用makefile引起的recipe for target 很多文章写的是由于编译文件路径引起或者是makefile代码中的空格引起的 分析 但是如果makefile文件不是手动配置的而且源代码提供的&#xff0c;…...

小黑子—多媒体技术与运用基础知识三:数字图形图像处理技术

多媒体技术与运用3.0 多媒体系列第三章1. 颜色科学1.1 颜色的性质1.1.1 颜色的物理性质1.1.2颜色三特性1.1.3三原色与三补色 1.2 颜色空间1.2.1 与设备无关的颜色空间1.2.1 与设备相关的颜色空间 1.3 常见的多媒体系统颜色空间1.3.1 RGB颜色空间1.3.2 CMYK颜色模型1.3.3 HSB颜色…...

Nginx实现ChatGPT API代理

文章目录 一、前言说明二、前置准备三、nginx配置三、代理域名用途 一、前言说明 本篇文章可以直接用于公司生产级的使用&#xff0c;所需要的资源直接改为公司级的即可平替使用文章均已通过实践应用&#xff0c;保证文章准确性&#xff0c;但因不同环境的不同可能效果不一致可…...

FileNotFoundError: [Errno 2] No such file or directory: ‘dot‘

FileNotFoundError: [Errno 2] No such file or directory: ‘dot’ 在绘制树形结构图的时候出现上述报错&#xff1a;已安装环境为ubuntu&#xff0c;python3.9 解决方案&#xff1a; 1、在终端输入sudo apt-get install graphviz&#xff0c;按回车键&#xff0c;输入密码&a…...

【分布族谱】正态分布和二项分布的关系

文章目录 正态分布二项分布验证 正态分布 正态分布&#xff0c;最早由棣莫弗在二项分布的渐近公式中得到&#xff0c;而真正奠定其地位的&#xff0c;应是高斯对测量误差的研究&#xff0c;故而又称Gauss分布。测量是人类定量认识自然界的基础&#xff0c;测量误差的普遍性&am…...

7.设计模式之责任链模式

前言 责任链&#xff0c;即将能够处理同一类请求的对象连成一条链&#xff0c;所提交的请求沿着链传递&#xff0c; 链上的对象逐个判断是否有能力处理该请求&#xff0c;如果能则处理&#xff0c;如果不能则传递给链上的下一个对象。为了避免请求发送者与多个请求处理者耦合在…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...