你知道怎么样排序才能做到多快好省?


小智最近迷上了计算机算法,今天过来给大家讲讲排序算法。


准备讲排序算法之前,我们还是要先回顾一下排序这个概念。


排序是一门古老的科学。排序问题,用数学的方式可以表达如下


问题输入:给定n个数,a1,  a2,  a3, ..., an
要求输出:给出n个数的排列,a1', a2', a3', ..., an',使得 a1≤ a2≤ a3≤ ... ≤ an'


从更形象的角度来说,排序就是一群人站成一列,高的站前面,矮的站在后面。

一个家庭的所有成员按身高排列的示意图(小智实在找不到图了,画一个示意-_-)


关于排序,有几个描述算法特征的词语:

稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;

不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;

时间复杂度:一个算法执行所耗费的时间。

空间复杂度:运行完一个程序所需内存的大小。


ok,了解完排序的相关概念以后,我有一个新的问题了:如何评价一个算法?小智认为,可以用一个词语来形容一个优秀的算法:多快好省


什么是“多快好省”?我们从算法的角度来解析一下:


:能够可靠处理大规模的数据

:算法的时间复杂度要更低的

:算法实现要符合稳定性

:算法的空间复杂度要更低的


到底哪些算法能够符合“多快好省”这个目标呢?我们先看一下目前的算法分类:


基于比较的排序算法的特征总结

注:本文不讨论非基于比较算法,比如计数排序、桶排序和基数排序


“多”的角度:从数据量的处理性能来看,需要不受随机因素影响的算法。冒泡算法、插入排序、快速排序这三个算法最好情况和最坏情况相差了一个数量级,这种不可靠性可能影响数据处理的效率。

“快”的角度:从时间复杂度的角度来看,希尔排序、归并排序、快速排序、堆排序的算法复杂度比较好,均低于O(n2)。

“好”的角度:从稳定性的角度来看,归并排序、插入排序、冒泡排序是稳定的

“省”的角度:从空间复杂度的角度来看,冒泡排序、插入排序、希尔排序、堆排序,空间复杂度为O(1)。其中,值得注意的是,一般写法的归并排序,空间复杂度为O(n),经过优化以后,使用空间可以为O(1)。


大家都看出了我的倾向了吧?小智从“多快好省”这四个方面,分析发现,归并算法在这四个方面表现不错。这次小智决定跟大家探讨一下归并算法


为什么归并排序能够做到多快好省?


解答这个问题之前,我们先了解一下什么是归并排序。


归并算法(merge sort)是一个分治算法(divide and conquer algorithm),冯·诺依曼(John von Neumann )在1945年发明了这个算法。这个算法将已有序的子序列合并,得到完全有序的序列,即先使每个子序列有序,再使子序列段间有序。


实际上,归并算法的算法步骤非常简单:

第1步:拆分,把长度为n的输入序列分成两个长度为n/2的子序列

第2步:递归调用,对这两个子序列分别使用归并排序

第3步:合并,将两个排序好的子序列合并成一个最终的排序序列


这几步,我们来分别地讲一下:


什么是拆分?将一个长序列拆分成两个子序列。这个属于分治法中的“分”,将大问题降解为小问题。


将长序列拆分成两个子序列示意图


如果n为奇数,不能被2整除,可以将n/2向上取整,这个对算法没有影响。


有一个特殊情况是需要注意的:当子序列长度为1时,已经没有办法进行拆分了,可以直接执行下一步。


什么是递归调用?实际上是重复调用归并排序的程序。我们假想一下,在最开始的情况下,执行完第1步,长序列被拆分为2个子序列。接着执行第二步时,直接对子序列进行归并排序,那么下一步则是继续拆分子序列。如此下去,直至将长序列拆分到无法分拆的情形。


我们以图来说明会更加清晰一点:


归并算法递归调用的分拆效果


经过不断地递归调用,要处理的子序列长度越来越短,最后直至子序列长度为1。


有一个特殊情况是需要注意的:当子序列长度为1时,已经不需要继续调用归并排序了,因此可以直接跳过递归调用这个步骤。


什么是合并?是将两个排好序的子序列,合成一个也是排好序的序列。这个合并算法也是比较简单。


合并过程可以表述为:对于两个子序列,X和Y,其中X和Y都是升序排列,以及知道X和Y每个数据在原来长序列的位置,分别为Xp和Yp,如何将X和Y合并成一个稳定的升序排列?


由于这两个子序列都是升序排列,因此我们同时遍历这两个子序列,从遍历的位置各拿出一个数字,哪个数字小就把它拿出来插入合并序列中。如果遇到拿出来的两个数字相等的情况,则比较原来序列的位置,哪个小就把它拿出来即可。


按照上述合并步骤,我们可以写出合并伪代码了:

i = 1, j = 1, l = 1

申请一个临时变量temp,用于储存合并后序列

如果 X[i] < Y[j]: temp[l] = X[i], l = l + 1, i = i + 1

如果 X[i] < Y[j]: temp[l] = Y[j], l = l + 1, j = j + 1

如果 X[i] = Y[j]:

    如果 Xp[i] < Yp[j]: temp[l] = X[i], l = l + 1, i = i + 1

    如果 Xp[i] > Yp[j]: temp[l] = Y[j], l = l + 1, j = j + 1


我将合并流程补充到整个归并算法的执行流程当中,以图的形式做了一个示例:


归并排序整体流程示意图


归并排序我们了解完了,我们可以开始回答为什么归并排序能够表现如此出色:


“多”的角度:归并排序为什么能保证可靠地处理数据?


归并排序的拆分的流程,跟数据的原始排序没有关系,无论是最坏情况还是最好情况,时间复杂度都是一致的,能够稳定处理大量数据。


“快”的角度:归并排序的时间复杂度为什么是 O(n log n)?


设归并排序所消耗的时间为T(n),进行归并排序的拆分操作以后,将原来的问题划分为原来规模的二分之一,每一个划分出来的问题将耗费时间是T(n/2),最后把这两部分有序的数组合并在一起所花的时间为O(n),因此:


T(n) = 2×T(n/2) + O(n)


而划分次数最多可以有logn次,因此累加起来可得T(n) = O(n log n)


“好”的角度:归并排序为什么能保证稳定呢?


归并排序将序列分割到最小,而后将序列进行合并。假如两个数字是相等的,在分割子序列的时候,不会更改他们之间的相对位置;在合并子序列的时候,只要能够做到先将位置在前的数字放到合并数组,这样就保证了排序结果的稳定。


“省”的角度:归并排序为什么空间复杂度可以为O(1)?


归并排序虽然原始写法的确是这样的,但是算法是可以改造的,我们只需要做到原地排序就可以了,而对于归并排序而言,原地排序的关键是合并。归并排序的原来写法,当进行合并时,是申请一个临时空间,将合并的数据放到临时空间当中,这个算法复杂度为 O(n) 


实际上,合并过程可以直接使用已有的位置。假设我们要合并的两段数组还是[13, 23, 37, 54]和[11,17, 26,29],在归并算法里,它们可以看成一个连续的数组形式:


[13, 23, 37, 54, 11, 17, 26, 29]


首先我们检查两段数组的第一个数,发现13 > 11,那么11这个数要拿出来,原来是要放到临时空间的第一个位置,但我们可以利用数组已有的位置,将11直接移到数组的第一个位置,然后原来第一段数组往后移一个位置,这样数组变为


[11, 13, 23, 37, 54, 17, 26, 29]


而后我们继续按照这种方式,合并[13, 23. 37. 54]和[17, 26 29]这两段数组。


可以发现,这种方式空间复杂度只需一个临时变量,用于协助数字移动,因此空间复杂度为O(1)。当然这样优化增加了移动的次数,为了空间,就要损失时间了。


总结一下,归并排序是个宝,一个多快好省的排序算法,大家如果遇到数据排序问题,可以优先考虑它。当然,归并排序并不是全能的,在某些类型问题下,有些算法比归并排序表现更为出色,往后小智会给大家解读。


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

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

相关文章

C# 使用 Index 和 Range 简化集合操作

C# 使用 Index 和 Range 简化集合操作Intro有的语言数组的索引值是支持负数的&#xff0c;表示从后向前索引&#xff0c;比如&#xff1a;arr[-1]从 C# 8 开始&#xff0c;C# 支持了数组的反向 Index&#xff0c;和 Range 操作&#xff0c;反向 Index 类似于其他语言中的负索引…

我的小服务器

朋友做了一个工控机的板子&#xff0c;我要了一块来&#xff0c;自己加上了迅驰1.2G CPU&#xff0c;再从笔记本上拆了一个1G内存和老的移动硬盘 30G IDE&#xff0c;就算搭起了一个最简陋的服务器。此外我从破DVD光驱上拆了一块铁皮底板&#xff0c;打了几个洞&#xff0c;把主…

爱心助农|百万斤丑苹果紧急待售!谁能帮这些特困孩子熬过寒冷冬天?

题记&#xff1a;人们在猛兽横行的蛮荒年代&#xff0c;得以从树上回归地面&#xff0c;是人们守望相助的结果&#xff0c;也是人类能繁衍至今的原因在这个什么都讲究颜值的年代有这样一个东西却以“丑”、“但非常好吃”引起了我们的注意它便是山西临猗的冰糖心丑苹果还要一个…

微软开源AI诊断工具Error Analysis

喜欢就关注我们吧&#xff01;Error Analysis 使用机器学习技术&#xff0c;助数据科学家更好地了解模型错误模式。在 2020 年 5 月的微软 Build 大会上&#xff0c;微软推出了三个响应式的 AI&#xff08;Responsible AI&#xff0c;RAI&#xff09;工具包&#xff0c;这三个工…

【SDL的编程】VC环境搭建

SDL&#xff08;simple DirectMedia Layer&#xff09;是一个可跨平台的开源库&#xff0c;最近由于自己的兴趣&#xff0c;就把它windosXP下的环境搭建了下。PC&#xff1a;Mircrosoft Windows XP Service Pack3Platform&#xff1a;Mircrosoft Visual C 6.0SourceCode&#x…

# 保持最外层获取焦点_大事件!沈阳爱尔白内障焕晶诊疗中心正式启用,两位PanOptix三焦点人工晶体植入患者清晰见证!...

近日&#xff0c;沈阳爱尔眼科医院大东院区白内障焕晶诊疗中心正式投入使用&#xff01;由沈阳爱尔眼科医院大东院区业务院长朱建勋领衔的白内障手术团队始终与国内外一流水准保持同步&#xff0c;开创性引进了爱尔康AcrySof IQ PanOptix 新一代三焦点人工晶状体。中心最先入住…

使用 Tye 辅助开发 k8s 应用竟如此简单(六)

续上篇&#xff0c;这篇我们来进一步探索 Tye 更多的使用方法。本篇我们将进一步研究 Tye 与分布式应用程序运行时 Dapr 如何碰撞出更精彩的火花。巧了&#xff0c;巧了&#xff0c;真是巧了 今天正值 dapr 1.0 发布的日子。如果你暂时还不了解什么是 dapr。那不如通过以下简短…

BeetleX.WebFamily针对Web SPA应用的改进

BeetleX.WebFamily1.0在集成vueelementaxios的基础上添加应用页、窗体布局和登陆验证等功能。通过以上功能开发Web SPA应用时只需要编写vue控件和配置菜单即可实现应用开发。使用创建一个.net控制台项目&#xff0c;然后通过Nuget引入BeetleX.WebFamily1.0组件&#xff0c;并在…

php acl rbac,建站常用的用户权限管理模型ACL和RBAC的区别

常用的权限管理模型ACL和RBAC的区别1.ACLACL是最早也是最基本的一种访问控制机制&#xff0c;它的原理非常简单&#xff1a;每一项资源&#xff0c;都配有一个列表&#xff0c;这个列表记录的就是哪些用户可以对这项资源执行CRUD中的那些操作。当系统试图访问这项资源时&#x…

华为年终奖,小员工分百万!任正非:钱给多了,不是人才也变成了人才!

华为今年又提前发了巨额年终奖&#xff0c;并公布了新的奖金方案&#xff0c;23级奖金额有近百万&#xff0c;并且宣称“上不封顶、绝不拖欠”&#xff0c;一时间引起热议。任正非签发的内部文件&#xff1a;华为不搞按资排辈&#xff0c;只要做出突出贡献&#xff0c;在新方案…

Redis缓存穿透、缓存雪崩、缓存击穿好好说说

前言 Redis是目前非常流行的缓存数据库啦&#xff0c;其中一个主要作用就是为了避免大量请求直接打到数据库&#xff0c;以此来缓解数据库服务器压力&#xff1b;用上缓存难道就高枕无忧了吗&#xff1f;no,no,no&#xff0c;没有这么完美的技术&#xff0c; 缓存穿透、缓存雪崩…

这是“我”的故事 —— 董彬

点击蓝字 关注我们作者&#xff1a;董彬校对/文章优化&#xff1a;刘轶民排版&#xff1a;Rani视频地址&#xff1a;https://www.bilibili.com/video/BV1NK4y1p7Ys与世界周旋的程序员大家好&#xff0c;我叫董彬 &#xff0c;现就职于野村信息&#xff0c; Title 是 Senior …

我用Python玩小游戏“跳一跳”,瞬间称霸了朋友圈!

“从前几天微信最新版本 6.6.1 的更新开始&#xff0c;微信小程序游戏“跳一跳”似乎在一夜之间风靡了朋友圈。它甚至比五六年前的飞机大战游戏都火爆&#xff0c;这种小游戏的火爆不仅仅是因为有魔性、有意思&#xff0c;更重要的是可以进行好友 PK&#xff01;“跳一跳”的小…

expsky.php,Typecho漏洞利用工具首发,半分钟完成渗透

原标题&#xff1a;Typecho漏洞利用工具首发&#xff0c;半分钟完成渗透*本文原创作者&#xff1a;expsky&#xff0c;本文属FreeBuf原创奖励计划&#xff0c;未经许可禁止转载声明&#xff1a;本工具由expsky原创&#xff0c;仅用于技术研究&#xff0c;不恰当使用会对网站造成…

BeetleX之Web网关1.5.7安装使用

新版的网关主要升级到BeetleX最新版提高http协议的解释性能&#xff0c;从而让网关的吞吐能力进一步提升&#xff0c;在功能界面上也做了简单的调整让操作更方便&#xff0c;修复linux下无权限启动进程问题。如果在windows上不想用IIS&#xff0c;linux下用nginx怕麻烦&#xf…

费马大定理,集惊险与武侠于一体

悬案费马大定理从提出到证明的过程&#xff0c;就是一部不折不扣的惊险小说。一个读者&#xff0c;在自己看过的书空白处留下附注。除了他自己&#xff0c;还有谁会关注呢&#xff1f;但是&#xff0c;法国人费马死后&#xff0c;他在一本《算术》书上所写的注记并没有随之湮没…

全国计算机技术与软件专业技术资格(水平)考试基础知识

全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试基础知识 -------------------------------------------------------------------------------- 1、什么是计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff1f;  计算机技术与软件专…

GPU迎来投资热潮 退潮后谁在裸泳

近期&#xff0c;数家GPU设计公司获得资本青睐&#xff0c;摩尔线程完成数轮投资获得数十亿元&#xff0c;无独有偶&#xff0c;壁仞科技宣布完成总额11亿元的A轮融资&#xff0c;沐曦集成电路宣布完成近亿元天使轮融资&#xff0c;登临科技宣布完成A轮融资。另外&#xff0c;天…

All in AI, 一句话看出了百度的野心,也看到了人工智能人才的未来

最近几天&#xff0c;在 2018 CES科技盛会上&#xff0c;百度无人驾驶系统 Apollo 2.0 正式开放&#xff0c;百度COO 陆奇表示&#xff0c;借着 Apollo 平台&#xff0c;他想打造中国无人车国家队&#xff01;All in AI, 一句话看出了百度的野心。而百度&#xff0c;只是 China…

知名Node.js组件存在代码注入漏洞

喜欢就关注我们吧&#xff01;日前&#xff0c;一个被大量下载的 Node.js 组件被发现其含有一个高危的代码注入漏洞。该漏洞被追踪为 CVE-2021-21315&#xff0c;影响了「systeminformation」npm 组件的安全性&#xff0c;该组件每周的下载量约为 80 万次&#xff0c;自诞生以来…