归并排序和快速排序的两种实现
在此之前我们已经介绍过归并排序和快速排序:浅谈归并排序与快速排序,但其中的实现都是基于递归的。本文将重新温故这两种算法并给出基于迭代的实现。
目录
- 1. 归并排序
- 1.1 基于递归
- 1.2 基于迭代
- 2. 快速排序
- 2.1 基于递归
- 2.2 基于迭代
1. 归并排序
1.1 基于递归
归并排序的核心是二路归并,实现二路归并需要一个额外的辅助数组,因此空间复杂度是 O ( n ) O(n) O(n)。
void merge(vector<int>& a, int l, int mid, int r, vector<int>& tmp) {int i = l, j = mid + 1, k = l;while (i <= mid && j <= r) {if (a[i] <= a[j]) tmp[k++] = a[i++];else tmp[k++] = a[j++];}while (i <= mid) tmp[k++] = a[i++];while (j <= r) tmp[k++] = a[j++];for (int i = l; i <= r; i++) a[i] = tmp[i];
}
该函数会对数组 a 的 [l, mid] 和 [mid + 1, r] 两部分进行二路归并,其中辅助数组 tmp 的大小与 a 相同。
有了 merge 函数,我们就可以很方便的实现归并排序了:
void merge_sort(vector<int>& a, int l, int r, vector<int>& tmp) {if (l >= r) return;int mid = l + r >> 1;merge_sort(a, l, mid, tmp), merge_sort(a, mid + 1, r, tmp);merge(a, l, mid, r, tmp);
}
1.2 基于迭代
很明显,基于递归的实现是自顶向下的,而基于迭代的实现是自底向上的。
我们可以先枚举区间长度,再枚举区间左端点。一开始每个区间的长度是 1 1 1,我们每次对相邻的两个区间进行二路归并,每归并一次区间的长度就是原先的两倍,所以枚举区间长度时变量 len 的更新方式为 len *= 2。
对于区间左端点,每合并完两个区间后,左端点就要更新成下下个区间,如下图所示:
还需保证 mid < n - 1,即 l < n - len。
void merge_sort(vector<int>& a) {int n = a.size();vector<int> tmp(n);for (int len = 1; len < n; len *= 2) {for (int l = 0; l < n - len; l += 2 * len) {int mid = l + len - 1;int r = min(l + 2 * len - 1, n - 1);merge(a, l, mid, r, tmp);}}
}
归并排序的时间复杂度是 O ( n log n ) O(n\log n) O(nlogn),无论是递归还是迭代,空间复杂度都是 O ( n ) O(n) O(n)。
2. 快速排序
2.1 基于递归
void quick_sort(vector<int>& a, int l, int r) {if (l >= r) return;int mid = l + r >> 1;int i = l - 1, j = r + 1, x = a[mid];while (i < j) {while (a[++i] < x);while (a[--j] > x);if (i < j) swap(a[i], a[j]);}quick_sort(a, l, j), quick_sort(a, j + 1, r);
}
2.2 基于迭代
void quick_sort(vector<int>& a, int l, int r) {if (l >= r) return;stack<pair<int, int>> stk;stk.emplace(l, r);while (!stk.empty()) {auto [l, r] = stk.top();stk.pop();if (l < r) {int mid = l + r >> 1;int i = l - 1, j = r + 1, x = a[mid];while (i < j) {while (a[++i] < x);while (a[--j] > x);if (i < j) swap(a[i], a[j]);}stk.emplace(l, j);stk.emplace(j + 1, r);}}
}
时间复杂度是 O ( n log n ) O(n\log n) O(nlogn),空间复杂度是 O ( log n ) O(\log n) O(logn)。
相关文章:
归并排序和快速排序的两种实现
在此之前我们已经介绍过归并排序和快速排序:浅谈归并排序与快速排序,但其中的实现都是基于递归的。本文将重新温故这两种算法并给出基于迭代的实现。 目录 1. 归并排序1.1 基于递归1.2 基于迭代 2. 快速排序2.1 基于递归2.2 基于迭代 1. 归并排序 1.1 基…...
C#,《小白学程序》第十四课:随机数(Random)第一,几种随机数的计算方法与代码
1 文本格式 /// <summary> /// 《小白学程序》第十四课:随机数(Random)第一,几种随机数的计算方法与代码 /// 本课初步接触一下随机数。 /// </summary> /// <param name"sender"></param> ///…...
[杂谈]-快速了解Modbus协议
快速了解Modbus协议 文章目录 快速了解Modbus协议1、为何 Modbus 如此受欢迎2、范围和数据速率3、逻辑电平4、层数5、网络与通讯6、数据帧格式7、数据类型8、服务器如何存储数据9、总结 Modbus 是一种流行的低速串行通信协议,广泛应用于自动化行业。 该协议由 Mo…...
WhatsApp的两个商业模式该如何选择
WhatsApp Business 是什么 目前 WhatsApp 提供两种商业模式,企业应根据自身需求选择相应版本。 第一个版本是 WhatsApp Business:初创企业只需一个手机应用程序,便可以个体单位与客户轻松互动; 另一个版本是 WhatsApp Business APIÿ…...
动态表单设计
动态表单设计 背景方案讨论基于上面分析,对比调研,自定义动态表单数据模型表单详解(一) 表单模板:jim_dynamic_form(二)表单数据类型:jim_form_data_type(三)…...
JAR will be empty - no content was marked for inclusion!
现象 在对自建pom依赖组件打包时,出现JAR will be empty - no content was marked for inclusion!错误。 方案 在pom中怎么加packaging标签内容为pom,标识只打包pom文件 <?xml version"1.0" encoding"UTF-8"?> ...<grou…...
软件生命周期及流程【软件测试】
软件的生命周期 软件生命周期是软件开始研制到最终被废弃不用所经历的各个阶段。 瀑布型生命周期模型 规定了它们自上而下、相互衔接的固定次序,如同瀑布流水,逐级下落,具有顺序性和依赖性。每个阶段规定文档并需进行评审。 特点ÿ…...
2023高教社杯数学建模E题思路代码 - 黄河水沙监测数据分析
# 1 赛题 E 题 黄河水沙监测数据分析 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变 化和人民生活的影响, 以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾 等方面都具有重要的理论指导意义。 附件 1 给出了位…...
双翌保养码使用指南方法(一)
保养码使用指南一 为了确保软件的正常运行和有效使用,正确地使用保养码是至关重要的。以下是保养码使用的简单指南,以帮助您进行正确的操作。 1. 打开软件入口:首先,在您的电脑上打开文件夹,并找到s-y softactive tool…...
hive指定字段插入数据,包含了分区表和非分区表
1、建表 语句如下: CREATE EXTERNAL TABLE ods_lineitem_full (l_shipdate date,l_orderkey bigint,l_linenumber int,l_partkey int,l_suppkey int,l_quantity decimal(15, 2),l_extendedprice decimal(15, 2),l_discount de…...
浏览器端vscode docker搭建(附带python环境)
dockerfile from centos:7 #安装python环境 run yum -y install wget openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel zlib-devel libffi-devel gcc make run wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz run tar -xvf Python-3.9.…...
Echarts图表跟随父容器的变化自适应
如果页面中有多个图表 隐藏/展开左边侧边栏echarts图表自适应 <div class"line"><div class"title">制冷站关键参数</div><div id"chartLine1" style"width: 100%;height:85%;"></div></div><…...
【多线程】ThreadLocal是什么?有哪些使用场景?使用ThreadLocal需要注意些什么?
文章目录 前言一、ThreadLocal 是什么?二、有哪些使用场景?三、实现原理四、在线程池中使用 ThreadLocal 为什么可能导致内存泄露呢?五、线程池中,如何正确使用 ThreadLocal?六、ThreadLocal 核心方法 前言 一、Threa…...
一种基于动态代理的通用研发提效解决方案
作为一名研发人员,除了业务开发之外,研发提效是一个永恒的话题,而女娲正是这一话题下进行的一次全面的剖析和实践。 作者:张全洪(钝悟) 一、女娲是什么 女娲是业务研发同学(开发、测试、运维)在软件迭代的…...
【vue3】一些关于hooks的使用经验
前言 最近接到了一个需求,隔壁嵌入式部门希望我们用前端解析渲染Kconfig表单。这篇文章用来记录一下本次使用hook pinia vue3的经验 hooks hooks的概念最早是在 React 中听到的,虽然早些时间也写过一点react,但也只是照葫芦画瓢…...
面试系列 - Java 并发容器详解
Java 并发容器是一组用于在多线程环境下安全访问和操作数据的数据结构。它们提供了线程安全的集合和映射,使开发者能够更轻松地处理并发编程问题。 一、Java并发容器 ConcurrentHashMap: 它是一个高效的并发哈希表,支持多线程并发操作而不需…...
使用动态住宅代理还能带来哪些好处?
一、什么是动态住宅代理ip 动态住宅代理是一种代理技术,它利用代理服务器中转用户和目标服务器之间的网络流量,实现用户真实位置的屏蔽。代理提供商会有自己的ip大池子,当你通过代理服务器向网站发送请求时,服务器会从池子中选中…...
笙默考试管理系统-MyExamTest----codemirror(18)
笙默考试管理系统-MyExamTest----codemirror(18) 目录 一、 笙默考试管理系统-MyExamTest----codemirror 二、 笙默考试管理系统-MyExamTest----codemirror 三、 笙默考试管理系统-MyExamTest----codemirror 四、 笙默考试管理系统-MyExamTest---…...
TGA格式文件转材质
今天淘宝上买了一个美女的模型,是blender的源文件,上面说有fbx格式的。我用unity,所以觉得应该可以用。文件内容如下图: FBX文件夹打开后,内容如下图所示,当时就预感到可能没有色彩。 unity打开后果然发现只…...
IP应用场景查询API:深入了解网络用户行为的利器
前言 随着数字时代的不断发展,互联网已经成为人们生活的重要组成部分。而随着越来越多的业务和社交活动迁移到在线平台上,了解和理解网络用户行为变得至关重要。为了满足这个需求,IP 应用场景查询 API 崭露头角,成为深入了解网络…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
