归并排序:数据排序的高效之道
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,
15年
工作经验,精通Java编程
,高并发设计
,Springboot和微服务
,熟悉Linux
,ESXI虚拟化
以及云原生Docker和K8s
,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea
归并排序:数据排序的高效之道
一、引言
在当今数字化时代,数据处理的规模和复杂性呈指数级增长。无论是处理海量的商业数据、科学研究中的实验数据,还是日常应用程序中的用户信息,排序算法都扮演着至关重要的角色。排序能够将无序的数据转换为有序的序列,从而使得数据的查找、分析和处理变得更加高效和便捷。
归并排序作为一种经典且高效的排序算法,在众多领域都有着广泛的应用。它基于“分治”这一强大的思想策略,通过将大规模的问题逐步分解为更小的子问题,然后分别解决这些子问题,最后将子问题的解合并起来得到原问题的解。这种思想不仅在排序算法中大放异彩,在许多其他复杂的算法设计场景中也被频繁借鉴。
想象一下,在一个大型电商平台的订单处理系统中,每天都有海量的订单数据需要按照订单时间、金额或者客户优先级等进行排序。归并排序能够快速而稳定地对这些数据进行整理,使得商家可以清晰地了解订单的顺序,从而更好地安排发货、库存管理等后续工作。又比如在基因测序领域,大量的基因片段数据需要按照特定的顺序进行排列组合,归并排序可以高效地完成这一任务,为后续的基因分析和疾病研究提供有力支持。
在本文,我们将深入探讨归并排序的原理、详细剖析其代码实现,并全面分析它的时间复杂度、空间复杂度以及其他特性,还会将其与其他常见的排序算法进行对比,从而让您全方位地了解归并排序这一重要的数据处理工具。
二、归并排序的原理
(一)分治思想的核心
归并排序的核心在于“分治”。它将一个未排序的数组不断地分割成更小的子数组,直到每个子数组只包含一个元素。这就像是把一个大任务逐步拆解成一个个极小的、易于处理的子任务。例如,对于一个包含 8 个元素的数组 [5, 3, 8, 2, 9, 1, 7, 4]
,首先会被分割成两个子数组 [5, 3, 8, 2]
和 [9, 1, 7, 4]
,然后这两个子数组又会继续被分割,[5, 3, 8, 2]
会变成 [5, 3]
和 [8, 2]
,[9, 1, 7, 4]
会变成 [9, 1]
和 [7, 4]
,如此继续,直到每个子数组都只有一个元素,如 [5]
、[3]
、[8]
、[2]
、[9]
、[1]
、[7]
、[4]
。
(二)合并的巧妙过程
当子数组都分割到最小单位后,就开始了合并的过程。合并是归并排序的关键步骤,它将两个已经排序的子数组合并成一个更大的排序数组。比如有两个已排序的子数组 [2, 5]
和 [3, 8]
,我们创建一个新的空数组来存储合并后的结果。首先比较两个子数组的第一个元素,即 2 和 3,因为 2 较小,所以将 2 放入新数组,然后 [2, 5]
子数组的指针后移一位。接着比较 5 和 3,3 较小,将 3 放入新数组,[3, 8]
子数组指针后移。再比较 5 和 8,5 较小,放入新数组,此时 [2, 5]
子数组的元素已全部处理完,直接将 [3, 8]
子数组剩余的 8 放入新数组,最终得到合并后的排序数组 [2, 3, 5, 8]
。
(三)归并排序算法
归并排序根据 “分而治之” 原则运行:
首先,我们将要排序的元素分为两半。然后,将生成的子数组再次划分 - 直到创建长度为 1 的子数组:
现在,两个子数组已合并,以便从每对子数组创建一个排序数组。在最后一步中,合并原始数组的两半,以便对整个数组进行排序。
在下面的示例中,您将看到两个子数组如何合并为一个。
合并排序 合并示例
合并本身很简单:对于这两个数组,我们定义一个合并索引,它首先指向相应数组的第一个元素。显示这一点的最简单方法是使用示例(箭头表示合并索引):
将比较合并指针上的元素。两个中较小的一个(示例中的 1)被附加到一个新数组中,并且指向该元素的指针向右移动了一个字段:
现在,将再次比较指针上方的元素。这次 2 小于 4,因此我们将 2 附加到新数组中:
现在指针位于 3 和 4 上。3 更小,并附加到目标数组中:
现在 4 是最小的元素:
现在是 5:
在最后一步中,将 6 附加到新数组中:
两个排序的子数组被合并到排序的最终数组中。
三、归并排序的作用
(一)数据有序化的利器
归并排序的最主要作用就是将无序的数据转换为有序的数据。在很多数据处理场景中,有序的数据能够极大地提高数据查询和处理的效率。例如在数据库查询中,如果数据是按照特定的字段(如主键、索引字段)进行排序的,那么在进行范围查询、等值查询时,数据库引擎可以利用排序的特性快速定位到目标数据,减少查询的时间复杂度。
(二)为其他算法提供基础
归并排序得到的有序数据还可以作为其他更复杂算法的基础。比如在一些搜索算法中,有序的数据可以使用二分搜索等高效的搜索策略。在图像处理领域,对图像像素数据进行排序后,可以更方便地进行图像的边缘检测、特征提取等操作,因为有序的数据结构能够让算法更有规律地处理图像中的信息。
四、归并排序的使用场景
(一)大规模数据处理
在处理大规模数据时,归并排序的优势尤为明显。由于其时间复杂度为 O ( n log n ) O(n\log n) O(nlogn),即使数据量非常庞大,它也能够在相对合理的时间内完成排序任务。例如在大数据分析平台中,需要对海量的用户行为数据、日志数据等进行排序以便进行后续的分析挖掘,归并排序可以有效地处理这些数据,为数据分析提供有序的数据基础。
(二)稳定性要求高的场景
归并排序是一种稳定的排序算法,这意味着在排序过程中,相等元素的相对顺序不会改变。在一些对数据顺序稳定性有严格要求的场景中,归并排序是首选。比如在金融交易系统中,对于同一时间发生的多笔交易,如果按照交易金额进行排序,并且要求相同金额的交易按照交易时间的先后顺序排列,归并排序就能够很好地满足这一需求,确保交易数据的排序既按照金额有序,又不会打乱相同金额交易的时间顺序。
五、归并排序的代码实现
(一)Java 代码示例
以下是归并排序的 Java
代码实现:
public class MergeSort {// 归并排序的入口方法,接收一个数组作为参数public static void mergeSort(int[] arr) {// 调用递归的归并排序方法,传入数组、起始索引 0 和结束索引数组长度 - 1mergeSort(arr, 0, arr.length - 1);}// 递归的归并排序方法,用于对指定范围内的数组进行排序private static void mergeSort(int[] arr, int left, int right) {// 如果左索引小于右索引,说明子数组中至少有两个元素,需要继续分割if (left < right) {// 计算中间索引,用于将数组分割成两部分int mid = (left + right) / 2;// 对左半部分子数组进行递归排序mergeSort(arr, left, mid);// 对右半部分子数组进行递归排序mergeSort(arr, mid + 1, right);// 合并两个已排序的子数组merge(arr, left, mid, right);}}// 合并两个已排序子数组的方法private static void merge(int[] arr, int left, int mid, int right) {// 计算左子数组的长度int leftLen = mid - left + 1;// 计算右子数组的长度int rightLen = right - mid;// 创建临时数组来存储左子数组和右子数组的元素int[] leftArr = new int[leftLen];int[] rightArr = new int[rightLen];// 将原数组中的左子数组元素复制到临时左子数组for (int i = 0; i < leftLen; i++) {leftArr[i] = arr[left + i];}// 将原数组中的右子数组元素复制到临时右子数组for (int j = 0; j < rightLen; j++) {rightArr[j] = arr[mid + 1 + j];}// 初始化合并索引,分别指向左子数组和右子数组的起始位置int leftPos = 0;int rightPos = 0;// 初始化合并后的数组索引,指向合并后数组的起始位置int mergeIndex = left;// 比较左子数组和右子数组的元素,将较小的元素放入原数组while (leftPos < leftLen && rightPos < rightLen) {if (leftArr[leftPos] <= rightArr[rightPos]) {arr[mergeIndex] = leftArr[leftPos];leftPos++;} else {arr[mergeIndex] = rightArr[rightPos];rightPos++;}mergeIndex++;}// 如果左子数组还有剩余元素,将其全部放入原数组while (leftPos < leftLen) {arr[mergeIndex] = leftArr[leftPos];leftPos++;mergeIndex++;}// 如果右子数组还有剩余元素,将其全部放入原数组while (rightPos < rightLen) {arr[mergeIndex] = rightArr[rightPos];rightPos++;mergeIndex++;}}
}
在上述代码中:
mergeSort
方法是对外公开的入口方法,它接收一个数组并调用递归的mergeSort
方法开始排序过程,传入数组的起始索引 0 和结束索引arr.length - 1
。- 递归的
mergeSort
方法首先检查子数组是否至少有两个元素,如果是,则计算中间索引mid
,将数组分割成左右两部分,然后分别对左右子数组进行递归排序,最后调用merge
方法合并两个已排序的子数组。 merge
方法首先创建两个临时数组来存储左右子数组的元素,然后通过循环比较两个临时数组中的元素,将较小的元素放入原数组中对应的位置,当其中一个临时数组的元素全部处理完后,将另一个临时数组剩余的元素全部放入原数组。
(二)Python 代码示例
def merge_sort(arr):# 如果数组长度大于 1,则进行排序if len(arr) > 1:# 计算中间索引mid = len(arr) // 2# 分割左子数组left_half = arr[:mid]# 分割右子数组right_half = arr[mid:]# 递归地对左子数组进行归并排序merge_sort(left_half)# 递归地对右子数组进行归并排序merge_sort(right_half)# 初始化索引,分别用于左子数组、右子数组和合并后的数组i = j = k = 0# 比较左子数组和右子数组的元素,将较小的元素放入原数组while i < len(left_half) and j < len(right_half):if left_half[i] <= right_half[j]:arr[k] = left_half[i]i += 1else:arr[k] = right_half[j]j += 1k += 1# 如果左子数组还有剩余元素,将其全部放入原数组while i < len(left_half):arr[k] = left_half[i]i += 1k += 1# 如果右子数组还有剩余元素,将其全部放入原数组while j < len(right_half):arr[k] = right_half[j]j += 1k += 1# 测试归并排序
arr = [5, 3, 8, 2, 9, 1, 7, 4]
merge_sort(arr)
print(arr)
在 Python
代码中:
- 首先判断数组长度是否大于 1,如果是则计算中间索引
mid
,将数组分割成左右两半。 - 然后分别递归地对左右子数组进行归并排序。
- 接着通过循环比较左右子数组的元素,将较小的元素放入原数组
arr
中,使用三个索引i
、j
、k
分别跟踪左子数组、右子数组和合并后数组的位置。 - 最后处理左右子数组剩余元素的情况,将它们依次放入原数组。
六、归并排序的时间复杂度分析
(一)分割过程的时间消耗
在归并排序中,分割过程是不断地将数组一分为二。对于一个包含 n n n 个元素的数组,每次分割都将问题规模减半。设分割的次数为 k k k,则有 n = 2 k n = 2^k n=2k,通过对数运算可得 k = log 2 n k=\log_2 n k=log2n。每次分割的操作时间复杂度相对较低,可以看作是常数时间,所以分割过程总的时间复杂度为 O ( log n ) O(\log n) O(logn)。
(二)合并过程的时间消耗
合并过程是将两个已排序的子数组合并成一个更大的排序数组。在合并时,对于长度为 n n n 的数组,需要遍历每个元素一次,所以合并过程的时间复杂度为 O ( n ) O(n) O(n)。
(三)总体时间复杂度
由于归并排序的分割过程时间复杂度为 O ( log n ) O(\log n) O(logn),合并过程时间复杂度为 O ( n ) O(n) O(n),并且在每一层的分割后都需要进行合并操作,所以总的时间复杂度为 O ( n log n ) O(n\log n) O(nlogn)。这意味着无论输入数组是有序、逆序还是随机排列,归并排序的时间复杂度都保持在 O ( n log n ) O(n\log n) O(nlogn) 这一相对高效的水平。
七、归并排序的空间复杂度分析
(一)临时数组的空间需求
在归并排序的合并过程中,需要创建临时数组来存储左右子数组的元素。在最坏的情况下,当对一个包含 n n n 个元素的数组进行排序时,临时数组的大小可能达到 n n n 个元素的规模。例如,在最后一次合并时,左右子数组的长度之和可能接近 n n n。
(二)总体空间复杂度
因此,归并排序的空间复杂度为 O ( n ) O(n) O(n),这是因为在排序过程中需要额外的空间来存储临时数组中的元素。与一些原地排序算法(如冒泡排序、插入排序在某些优化情况下)相比,归并排序需要更多的额外空间,但它换来的是更高效的时间复杂度。
八、归并排序的其他特性
(一)稳定性
归并排序是一种稳定的排序算法。在合并过程中,当左右子数组的元素相等时,先将左子数组的元素放入合并后的数组。这就保证了相等元素在排序前后的相对顺序不会改变。例如,对于数组 [(3, 'a'), (3, 'b'), (5, 'c')]
,按照元素的第一个值进行排序时,归并排序会确保 (3, 'a')
在 (3, 'b')
之前,即使它们的第一个值相等。
(二)并行性
归并排序具有一定的并行性潜力。由于其分治的特性,可以将不同的子数组分割任务分配给不同的处理器核心或者线程来并行处理。例如,在对一个非常大的数组进行排序时,可以将数组分割成多个子数组,然后让多个线程同时对这些子数组进行归并排序,最后再将各个线程排序好的子数组合并起来。不过,在实际实现并行归并排序时,需要考虑线程同步、负载均衡等问题,以确保并行计算的效率。
九、归并排序与其他排序算法的对比
(一)与冒泡排序对比
冒泡排序是一种简单的比较排序算法,它的时间复杂度在最坏情况下为 O ( n 2 ) O(n^2) O(n2),平均情况下也为 O ( n 2 ) O(n^2) O(n2)。而归并排序的时间复杂度为 O ( n log n ) O(n\log n) O(nlogn),在大规模数据排序时,归并排序的效率远远高于冒泡排序。例如,当对 10000 个元素进行排序时,冒泡排序可能需要进行大量的元素比较和交换操作,时间消耗巨大,而归并排序则能够在相对较短的时间内完成排序任务。
(二)与插入排序对比
插入排序在最好情况下(数组已经部分有序)时间复杂度为 O ( n ) O(n) O(n),但在最坏和平均情况下时间复杂度为 O ( n 2 ) O(n^2) O(n2)。归并排序在任何情况下都保持 O ( n log n ) O(n\log n) O(nlogn) 的时间复杂度。而且插入排序是一种原地排序算法,空间复杂度为 O ( 1 ) O(1) O(1),而归并排序空间复杂度为 O ( n ) O(n) O(n)。在数据量较小且数组可能已经部分有序的情况下,插入排序可能表现较好,但对于大规模数据,归并排序更具优势。
(三)与快速排序对比
快速排序在平均情况下时间复杂度为 O ( n log n ) O(n\log n) O(nlogn),并且它是一种原地排序算法,空间复杂度在平均情况下为 O ( log n ) O(\log n) O(logn)。然而,快速排序在最坏情况下时间复杂度会退化为 O ( n 2 ) O(n^2) O(n2),例如当数组已经有序或者逆序时。而归并排序始终保持 O ( n log n ) O(n\log n) O(nlogn) 的时间复杂度,并且是稳定的。在数据随机分布且对稳定性要求不高的情况下,快速排序可能因为其原地特性和较好的平均性能而更常用,但在稳定性要求高或者数据可能出现最坏情况的场景下,归并排序则是更好的选择。
十、总结
归并排序作为一种经典的排序算法,以其高效的时间复杂度 O ( n log n ) O(n\log n) O(nlogn)、稳定的排序特性以及分治的巧妙思想,在数据处理领域占据着重要的地位。
相关文章:

归并排序:数据排序的高效之道
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...

【redis初阶】浅谈分布式系统
目录 一、常见概念 1.1 基本概念 2.2 评价指标(Metric) 二、架构演进 2.1 单机架构 2.2 应用数据分离架构 2.3 应用服务集群架构 2.4 读写分离/主从分离架构 2.5 引入缓存 ⸺ 冷热分离架构 2.6 数据库分库分表 2.7 业务拆分 ⸺ 引入微服务 redis学习&…...

CatLog的使用
一 CatLog的简介 1.1 作用 CAT(Central Application Tracking) 是基于 Java 开发的实时应用监控平台,为美团点评提供了全面的实时监控告警服务。 1.2 组成部分 1.2.1 Transaction 1.Transaction 适合记录跨越系统边界的程序访问行为&a…...
头歌python实验:网络安全应用实践-恶意流量检测
第1关:re 库的使用 本关任务:编写一个能正则匹配出 ip 地址的小程序。 re 的主要功能函数 常用的功能函数包括: compile、search、match、split、findall(finditer)、sub(subn)。 re.search 函数 re.search 扫描整个字符串并返回第一个成功的匹配。 函数语法: re…...

大模型WebUI:Gradio全解11——Chatbots:融合大模型的多模态聊天机器人(2)
大模型WebUI:Gradio全解11——Chatbots:融合大模型的聊天机器人(2) 前言本篇摘要11. Chatbot:融合大模型的多模态聊天机器人11.2 使用流行的LLM库和API11.2.1 Llama Index11.2.2 LangChain11.2.3 OpenAI1. 基本用法2. …...

如何用 Python 实现简单的 AI 模型?
💖 欢迎来到我的博客! 非常高兴能在这里与您相遇。在这里,您不仅能获得有趣的技术分享,还能感受到轻松愉快的氛围。无论您是编程新手,还是资深开发者,都能在这里找到属于您的知识宝藏,学习和成长…...

单片机-直流电机实验
1、ULN2003芯片介绍 ULN2003, 该芯片是一个单片高电压、高电流的达林顿晶体管阵列集成电路。不仅可以用来 驱动直流电机,还可用来驱动五线四相步进电机。支持驱动大功率电器 因为 ULN2003 的输出是集电极开路,ULN2003 要输出高电平࿰…...
python【数据结构】
1. 列表 Python 中列表是可变的,这是它区别于字符串和元组的最重要的特点;即,列表可以修改,而字符串和元组不能。 以下是 Python 中列表的方法: 方法描述list.append(x)把一个元素添加到列表的结尾,相当…...

详解Sonar与Jenkins 的集成使用!
本文阅读前提 本文假设读者熟悉Jenkins和SonarQube的基础操作。 核心实现功能 Jenkins中运行的job来调用SonarScanner,最后可实现测试结果与SonarQube中同步查看。 Jenkins中安装Sonar相关插件 配置Sonarqube Dashboard>Manage Jenkins>Systems 指定son…...

《笔记》青蛙跳台阶——斐波那契数列
斐波那契数列 斐波那契数列(Fibonacci Sequence)是一个经典的数学数列,其特点是每一项都是前两项的和。数列的前两项通常定义为 0 和 1(或 1 和 1),后续每一项都是前两项的和。 斐波那契数列的定义 斐波那…...

SpringBoot3动态切换数据源
背景 随着公司业务战略的发展,相关的软件服务也逐步的向多元化转变,之前是单纯的拿项目,赚人工钱,现在开始向产品化\服务化转变。最近雷袭又接到一项新的挑战:了解SAAS模型,考虑怎么将公司的产品转换成多租…...

OSPF - 特殊区域
OSPF路由器需要同时维护域内路由、域间路由、外部路由信息数据库。当网络规模不断扩大时,LSDB规模也不断增长。如果某区域不需要为其他区域提供流量中转服务,那么该区域内的路由器就没有必要维护本区域外的链路状态数据库。 OSPF通过划分区域可以减少网…...
Linux 系统下磁盘相关指令:df、du、fdisk、lsblk
文章目录 I df、du、fdisk、lsblk指令df命令用于显示文件系统的磁盘空间使用情况du命令用于估算目录或文件的磁盘空间使用情况fdisk命令用于对磁盘进行分区操作lsblk指令查看设备信息II 应用du估算目录或文件的磁盘空间使用情况lsblk查看服务器上查看硬盘个数III 知识扩展磁盘阵…...
基于单片机的肺功能MVV简单测算
肺功能MVV一般是指肺部每分钟的最大通气量。 MVV本身是最大值的英文缩写,在临床上,肺功能MVV表示肺部每分钟最大通气量,用以衡量气道的通畅度,以及肺部和胸廓的弹性、呼吸肌的力量。 肺部每分钟的最大通气量的参考值男性与女性之…...

如何用Python编程实现自动整理XML发票文件
传统手工整理发票耗时费力且易出错,而 XML 格式发票因其结构化、标准化的特点,为实现发票的自动化整理与保存提供了可能。本文将详细探讨用python来编程实现对 XML 格式的发票进行自动整理。 一、XML 格式发票的特点 结构化数据:XML 格式发票…...

腾讯云AI代码助手编程挑战赛-百事一点通
作品简介 百事通问答是一款功能强大的智能问答工具。它依托海量知识储备,无论你是想了解生活窍门、学习难点,还是工作中的专业疑惑,只需输入问题,就能瞬间获得精准解答,以简洁易懂的方式呈现,随时随地为你…...
Spring学习笔记1
目录 1 什么是spring2 spring的优势3 IOC的概念和作用3.1 无参数构造函数的实例化方式3.2 使用工厂中的普通方法实例化对象 4 Bean4.1 Bean相关概念4.2 Bean对象的作用范围 5 DI5.1 构造函数注入5.2 set方法注入5.3 复杂类型数据注入5.4 基于注解的IOC5.4.1 包扫描5.4.2 Compon…...
LeetCode 2185. Counting Words With a Given Prefix
🔗 https://leetcode.com/problems/counting-words-with-a-given-prefix 题目 给一个字符串数组,返回其中前缀为 pref 的个数 思路 模拟 代码 class Solution { public:int prefixCount(vector<string>& words, string pref) {int count…...

图漾相机基础操作
1.客户端概述 1.1 简介 PercipioViewer是图漾基于Percipio Camport SDK开发的一款看图软件,可实时预览相机输出的深度图、彩色图、IR红外图和点云图,并保存对应数据,还支持查看设备基础信息,在线修改gain、曝光等各种调节相机成像的参数功能…...
前端开发中页面优化的方法
前端页面优化是指通过改进网页的加载速度、提高用户体验和SEO优化等手段来优化页面性能的过程。以下是一些常见的前端页面优化方法: 压缩和合并文件:通过压缩CSS和JavaScript文件,并将多个文件合并成一个文件,减少网络传输和HTTP请…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...