算法一——排序

文章出处:极客时间《数据结构和算法之美》-作者:王争。该系列文章是本人的学习笔记。

分析排序算法的角度

算法的执行效率

算法的执行效率一般从时间复杂度以及比较、交换次数来考虑。

时间复杂度

时间复杂度需要考虑最好情况、最坏情况、平均情况时间复杂度。同时我们需要考虑复杂度的系数、常数和低阶。这是因为时间复杂度反应的是数据规模n很大时候的一个增长趋势,所以会忽略系数、常数、低阶。但是实际软件开发中,n可能是10、100、1000。这个时候就不能忽略系数、常数、低阶。

比较、交换次数

我们常见的排序算法大多数是基于比较的。基于比较的排序算法会涉及比较和元素交换两种操作。所以需要考虑。

内存消耗

有些排序算法的空间消耗是O(1)的,有些是O(n)。原地排序是空间复杂度是O(1)的排序算法。

算法的稳定性

排序算法的稳定性是指如果数组中有两个值相同的元素,经过排序算法排序之后,这两个元素的前后顺序不发生变化。这种排序算法叫做稳定的排序算法。如果前后顺序发生变化了,则称为不稳定性排序算法。
用途是:一般排序的是一个对象。例如希望按照订单金额从小到大排序订单,金额相同的时候按照订单时间从小到大排序。我们可以先按照订单时间从小到大排序,然后按照订单金额从小到大排序。如果是稳定的则可以实现这样的要求。

总结:考核的指标有:最好时间复杂度、最坏时间复杂度、平均时间复杂度、比较次数、交换次数、空间复杂度、算法稳定性。

基于比较的排序算法比较

有序度

数组中具有有序关系的元素对的个数。有序元素对的表示是这样的:

a[i]<=a[j],如果i<ja[i]<=a[j],如果i<ja[i]<=a[j]i<j
一个数组中最大的有序度是n∗(n−1)2\dfrac{n*(n-1)}{2}2n(n1),称为满有序度。
逆序度=满有序度-有序度

冒泡排序

特点:比较相邻元素,交换的也是相邻元素
空间复杂度:O(1),原地排序
稳定性:稳定(只要相邻元素相等不做交换)
最好时间复杂度:要排序的数组已经有序,需要冒泡一遍,O(n)。
最坏时间复杂度:顺序刚好相反,需要n次冒泡,O(n2n^2n2)。
平均时间复杂度:平均时间复杂度本来是一个加权平均值。但这里太过复杂,使用有序度来解决。
排序算法的时间复杂度主要由比较次数和交换次数决定。
因为每交换一次,数组的有序度加1。所以最少的交换次数是0,当输入完全有序。最多n∗(n−1)2\dfrac{n*(n-1)}{2}2n(n1),当输入完全无序。取个平均值表示初始有序度既不高也不低:n∗(n−1)4\dfrac{n*(n-1)}{4}4n(n1)。也就是说平均情况下需要n∗(n−1)4\dfrac{n*(n-1)}{4}4n(n1)次交换。
比较次数肯定多于交换次数,这个值的上限是O(n2n^2n2)。
所以平均时间复杂度是O(n2n^2n2)。

插入排序

特点:往一个有序的数组中插入一个元素。将数组分为有序区间和无序区间。
空间复杂度:O(1),原地排序
稳定性:稳定
最好时间复杂度:如果输入是已经排序好的,我们每次只在有序区间的末尾比较一次数据,所以是O(n)。注意:这里是从尾到头遍历已经排序好的数据。
最坏时间复杂度:如果是输入是逆袭的,相当于每次在数组的第一个位置插入元素,需要移动大量的数据。复杂度O(n2n^2n2)。
平均时间复杂度:在数组中插入一个数据的平均时间复杂度是O(n)(以前课程里面讨论过)。循环插入n次。所以复杂度O(n2n^2n2)。
一般项目中选择插入排序。因为插入排序的数据交换工作比较简单。随机生成 10000 个数组,每个数组中包含 200 个数据。在我电脑上,冒泡排序394ms,插入排序6ms。

选择排序

特点:将数组分为有序区间和无序区间。每次在无序区间选择最小元素插入在有序区间末尾。
空间复杂度:O(1),原地排序
稳定性:不稳定。找到的最小元素需要与前面的元素互换位置,可能改变相同元素的前后顺序。
最好时间复杂度:因为选择排序每次都需要在无序区间选择最小元素,所以每次都需要n次比较。需要重复n次。所以复杂度O(n2n^2n2)。
最坏时间复杂度:O(n2n^2n2)
平均时间复杂度:O(n2n^2n2)

归并排序

特点:使用分治、分区的思想。例如解决下标从p到q数组的排序问题,可以先解决从p到r,从r+1到q两个子数组的排序问题,然后将两个子数组合并,就解决了。
空间复杂度:因为合并部分需要单独申请空间,而最多申请O(n)。不是原地排序。
稳定性:只需要保证合并过程中相同元素前后位置不变,就可以保证稳定性。
时间复杂度:O(nlogn)。

快速排序

特点:使用分治、分区的思想。例如解决下标从p到q数组的排序问题。我们先选择一个pivot元素,可以是a[q]。小于pivot的元素放在左边,大于pivot的元素放在右边,pivot放在中间,位置假如是i。然后再递归的解决从p到i-1的排序问题,从i+1到q的排序问题。
递推公式:quick_sort(p…q) = quick_sort(p,i-1)+ quick_sort(i+1,q)
退出条件:p>=q
快速排序找到pivot元素的合适位置的函数是partition。这个函数的实现有一些技巧。
空间复杂度:O(1),原地排序
最好时间复杂度:最好的情况是pivot每次可以将数组一分为二,时间复杂度O(nlognnlognnlogn)。
最坏时间复杂度:如果每次pivot都将数组分成两部分(自己和其他部分),时间复杂度就是O(n2n^2n2)
平均时间复杂度:O(nlognnlognnlogn),以后的课程中会介绍。使用递归树来理解。
分治、分区思想的拓展:用来解决无序问题。例如查找一个无序数组的第k大元素。我们选择数组a[0…n-1]的最后一个元素a[n-1]作为pivot。对数组做原地拆分,变为a[0…p-1]、a[p]、a[p+1…n-1]。如果k=p+1,那么a[p]就是答案。如果k<p+1,那么答案在a[0…p-1]中,继续做分区。如果k>p+1,则答案在a[p+1…n-1],继续做分区。

快速排序vs归并排序

在这里插入图片描述
归并排序是由下到上,先处理子问题(的排序问题),然后再合并。
快速排序是由上到下,先分区,再处理子问题(的排序问题)。

如何优化快速排序

快排在某些情况下时间复杂度会退化为O(n2)O(n^2)O(n2)。这种时候是因为选取的pivot每次都将数组分成了自己和其他两个部分,如果选择的pivot合适就不会出现这样的情况。
1 三数取中法。可以选择头、尾、中间三个元素的中间值作为pivot。如果数组比较长,可以使用“五数取中法”、“十数取中法”。
2 随机法。从要排序的区间中每次随机选择一个数作为pivot。从概率角度讲,有选择不合适的时候,但不会每次都不合适。

快排可以优化的还有空间。快排使用的是递归,会因为栈大小的限制,引起栈溢出。可以在堆上模拟实现一个函数调用栈,手动模拟递归出栈、压栈的过程,这样就没有栈空间大小限制了。

线性排序算法

桶排序

特点:将要排序的数据放入几个桶,每个桶内的数据再单独排序。按照桶依次取出就实现了整体数据排序。
应用范围:1 要排序的数据能够很容易划分到m个桶。并且桶之间有天然的大小关系。2 各个桶的数据分布要均匀,如果集中在一个桶,那就没有意义了。3 比较适合外部排序,数据量太大,不能在内存中完成排序。
时间复杂度:在桶的个数m非常接近数组大小n的时候,接近O(n),实际是O(nlog(n/m))。
空间复杂度:O(n)
稳定性: 取决于每个桶的排序方式,快排就不稳定,归并就稳定。

计数排序

特点:是桶排序的特殊化。每个桶内放的值是相同的。例如考生排名。
时间复杂度:O(n)。
计数排序的计数方法是需要了解的。(图片来自极客时间)在这里插入图片描述

例如有8个考生,成绩分别是A[8]={2,5,3,0,2,3,0,3}。计算得到每个考生的排名。
1 用C[6]表示桶数组,遍历一遍得到C[6]={2,0,2,3,0,1}。
2 我们对C数组顺序求和得到C[6]={2,2,4,7,7,8}。C[k]存储小雨等于分数k的考生个数。
3 从后向前一次扫描数组A,k=A[i],idx=C[k]-1,R[idx]=k,C[k]=C[k]-1。这样就知道考试得分是k的考生,排名是idx。
代码

考生排名一般用JDK自带的排序算法即可实现。这样的时间复杂度一般为O(nlogn)。当成绩是一个整数的时候可以使用计数排序在O(n)时间内完成。代码

应用范围:计数排序只能用在数据范围不大的场景中。如果数据范围k比数组长度n大很多,就不适合了。计数排序只能给出非负整数的排序。如果要排序的数据是基于其他类型的,需要调整到非负整数的范围。
稳定性: 稳定,只要整理最后结果时从后开始遍历即可。

基数排序

特点:如果有10万个手机号码,从小到大排序。因为数据范围大,桶排序和计数排序都不适合。可以先按照最后一位排序,接着按照倒数第二位排序…一直到按照第一位排序。使用稳定排序算法。经过11次排序之后,手机号码就有序了。
应用范围:可以分割出单独的每一位,而且位之间有递进关系(a的高位大于b的高位=>a大于b)。每一位的数据范围不能太大,要可以使用线性排序。
时间复杂度:O(k*n)。每一位按照桶排序或者计数排序实现,需要排序k次。
稳定性:稳定,而且必须稳定。

业务思考题

1 为什么插入排序比冒泡排序更受欢迎?
2 用快排思想在O(n)内找第k大元素?
3 现在你有10个接口访问日志文件,每个文件大小约300MB,每个文件里的日志都是按照时间戳从小到大排序的。你希望将这10个较小的日志文件合并为1个日志文件,合并之后的日志仍然按照时间戳从小到大排序。如果处理上述排序任务的机器内存只有1GB,怎么做?
4 如何根据年龄给100万用户数据排序?
5 假设我们现在需要对D,a,F,B,c,A,z这个字符串进行排序,要求将其中所有小写字母都排在大写字母前面,但小写字母内部和大写字母内部不要求排序。

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

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

相关文章

第四十二期:Linux转正日常办公电脑到底行不行

昨天是中国程序员们自定义的程序员日&#xff0c;阿里在秀食堂&#xff0c;另一网络巨头腾讯也不甘寂寞地小蹭了一下这个节日&#xff1a;发布了Linux QQ 2.0 beta&#xff0c;宣告Linux版QQ回归。 作者&#xff1a;电脑报 昨天是中国程序员们自定义的程序员日&#xff0c;阿…

[Kali][VMware][2020][窗口大小][分辨率]高分辨率自适应

1.Vmware->查看->自动调整大小->自动适应窗口 2.Kali现在提供了HiDPI模式。此模式可调整GTK&#xff0c;QT甚至基于Java的界面的缩放比例&#xff0c;因此用户无需手动修改每个界面。您可以通过从应用程序菜单中打开“ Kali HiDPI模式”或kali-hidpi-mode从终端运行来…

第四十三期:Wireshark网络分析就这么简单,你一定会喜欢的技巧

拿到一个网络包时&#xff0c;我们总是希望它是尽可能小的。操作一个大包相当费时&#xff0c;有时甚至会死机。如果让初学者分析1GB以上的包&#xff0c;估计会被打击得信心全无。所以抓包时应该尽量只抓必要的部分。 作者&#xff1a;科技yuan 一、抓包 拿到一个网络包时&a…

Beta冲刺(9/7)——2019.5.31

作业描述 课程软件工程1916|W(福州大学)团队名称修&#xff01;咻咻&#xff01;作业要求项目Beta冲刺&#xff08;团队&#xff09;团队目标切实可行的计算机协会维修预约平台开发工具Eclipse团队信息 队员学号队员姓名个人博客地址备注221600207黄权焕https://www.cnblogs.co…

数据结构三——跳表

文章出处&#xff1a;极客时间《数据结构和算法之美》-作者&#xff1a;王争。该系列文章是本人的学习笔记。 跳表的由来 说明&#xff1a;图片来自极客时间 由来   二分查找的数据结构是数组&#xff0c;利用数组随机访问的特定查找的时间复杂度是O(logn)。如果数据结构是…

[BUGKU][CTF][MISC][2020] MISC writeup持续更新中

CTF总结 ctf基本操作&#xff1a;https://blog.csdn.net/mafucan/article/details/106886421 zip: https://www.anquanke.com/post/id/86211 找软件推荐网址 1.https://www.52pojie.cn/ 2.没有的话百度一下 去找百度云 工具下载&#xff1a; stegSolve 隐写分析 需要配置Java…

spring学习(1):初始项目

1打开idea----new project 2点击建立项目的类型maven 点击next 3点击next 4选择路径&#xff0c;点击完成 5建立成功之后修改pom.xml配置文件 添加&#xff0c;解决依赖关系 <dependencies><dependency><groupId>org.springframework</groupId><ar…

[密码学][困难问题][常见规约]密码学问题常见困难问题

参考网址(科学上网) 密码学问题常见困难问题,需要点击参考网址进行查找 其困难问题的介绍非常友好&#xff0c;请根据目录快速找到相关资料 以下是检索 目录 Discrete logarithm problem DLP: discrete logarithm problem CDH: computational Diffie-Hellman problem SDH:…

数据结构四——散列表(下)

文章出处&#xff1a;极客时间《数据结构和算法之美》-作者&#xff1a;王争。该系列文章是本人的学习笔记。 7 散列表链表的应用 很多情况下散列表会和链表一起使用。散列表可以通过key查找value。链表可以按照value进行排序。这样就能通过value查找key&#xff0c;也可以通…

spring学习(2):初始化spring程序

接着上一节的课程继续学习 MesasageService 类 package hello;import org.springframework.stereotype.Component; //注解的加入 Component public class MesasageService {public MesasageService() {super();System.out.println("MessageService...");}/*** 执行打…

Asp.Net Core 第05局:读取配置

前言 本文介绍Asp.Net Core 读取配置文件。环境 1.Visual Studio 2017 2.Asp.Net Core 2.2 开局 前期准备 1.添加app.json文件并在里面添加内容&#xff1b; 2.将app.json文件配置到应用中&#xff1b; 3.添加app.json对应的AppConfig类&#xff1b; 4.下面三种方式读取配置文…

[BUGKU][CTF][PWN][2020] PWN writeup

准备UBUNTU pwndbg pwntools PWN1 关键字&#xff1a;nc 知识点&#xff1a;nc使用方法 https://www.cnblogs.com/nmap/p/6148306.html nc命令是一个功能打包的网络实用程序&#xff0c;它通过命令行在网络上读取和写入数据;nc是为NMAP项目编写的&#xff0c;是目前已分裂的ne…

spring学习(3):获取bean对象

接着上一节的课程继续学习 MesasageService 类 package hello;import org.springframework.stereotype.Component; //注解的加入 Component public class MesasageService {public MesasageService() {super();System.out.println("MessageService...");}/*** 执行打…

数据结构四——散列表(上)

文章出处&#xff1a;极客时间《数据结构和算法之美》-作者&#xff1a;王争。该系列文章是本人的学习笔记。 1散列表的由来 从数组随机访问特性说起。  数组的随机访问特性是&#xff1a;数组a,a[5]可以直接访问到数组的第6个元素。这就类似于在下标和数组对应的值之间建立…

[BUGKU][CTF][Reverse][2020] Reverse writeup 1-7 暂时肝不动了

Reverse 入门逆向 步骤: ida main函数 按R Reverse signin 关键字&#xff1a; 知识点&#xff1a;Android逆向分析。&#xff08;常用工具&#xff1a;安卓模拟器、JEB、Cyberchef、Androidkiller&#xff09; 步骤: 1.用jeb打开&#xff0c;找到MainActivity&#xff0c;右…

spring学习(4):spring管理对象之间的关联关系

接着上一节的课程继续学习 MesasageService 类 package hello;import org.springframework.stereotype.Component; //注解的加入 Component public class MesasageService {public MesasageService() {super();System.out.println("MessageService...");}/*** 执行打…

[Lua]LuaAPI整理

ref &#xff1a;https://blog.csdn.net/ouyangshima/article/details/43339571 LUA和C/C的沟通桥梁——栈 Lua生来就是为了和C交互的&#xff0c;因此使用C扩展Lua或者将Lua嵌入到C当中都是非常流行的做法。要想理解C和Lua的交互方式&#xff0c;首先要回顾一下C语言是如何处理…

[hackinglab][CTF][基础关][2020] hackinglab 基础关 writeup

在线工具&#xff1a;https://www.qqxiuzi.cn/daohang.htm 基础关 1 key在哪里&#xff1f; 知识点&#xff1a;F12查看源代码 步骤:F12 基础关 2 再加密一次你就得到key啦~ 知识点&#xff1a;ROT13 步骤: 基础关 3 猜猜这是经过了多少次加密&#xff1f; 关键字&#xf…

spring学习(5):spring简介

1什么是spring 核心概念 spring框架组成

算法四——哈希

文章出处&#xff1a;极客时间《数据结构和算法之美》-作者&#xff1a;王争。该系列文章是本人的学习笔记。 哈希算法的定义 文章来自极客时间。 参考网页 定义&#xff1a;将任意长度的二进制值串映射为固定长度的二进制值串。映射之后的二进制值串称为哈希值。 符合几点要…