关于常见排序的一些细节的理解

news2024/11/16 11:45:45

最近复习了一下十种基本的排序算法,但是发现有很多的细节理解不到位,不是忘了而是根本没理解。就比如为啥有的排序是不稳定排序,而有的排序的时间复杂度高等等问题。



一、不稳定排序的稳定性分析和复杂度

常见排序算法中有4种排序是不稳定的。快速排序希尔排序堆排序选择排序

    • 快速排序

快速排序是一种不稳定的排序

1.1什么是快速排序

在一个无序数组里,我们先选择一个基准值(一般选择头一个数作为基准值),然后创建两指针,以这个基准值为标准,左指针找小于等于基准值的数,右指针找大于基准值的数,找到后,交换两个指针指向的数据,继续往后找,直到两个指针相遇为止,最后交换基准值和两指针共同指向的那个值。

1.2快速排序不稳定的原因

为啥说他不稳定呢,如果说出现两个一样的数,但是后面的数可能排到前面去,所以说他不稳定。

这里我们让小于等于基准值的数都排到基准值的前面了,所以最后6*会在基准值的前面,这样是不是就错了。如果我们把大于等于基准值的数排到基准值的后面就不会出现这样的错误。但是这个错误很可能出现,所以我们说快速排序是不稳定排序。

1.3时间复杂度分析:

最差情况:对于快速排序来说它的最差情况就是每次选择的基准值是数组中的最大值或者是最小值。假设每一次选择的都是最小值,那其他数的位置不变,然后序列的首位置就被固定。继续让剩下的n-1个元素占据2~n的位置,但是每次选择的还是最小值,以此类推。

对于n个数来说,需要操作n层,并且每一层要比较剩下的元素。所以时间复杂度时O(N^2) 。

最好情况:最好的情况就是,基准值正好能把整个无序数列平分成两截。

T(n)=2*T(n/2)+f(n);     T(n/2)是每一个子区间的时间,f(n)是分裂一个区间用的时间。

接下来的操作就和归并排序的一毛一样了。这里我就不再絮了,各位大佬就看最后面的归并排序吧。

时间复杂度是O(nlogn)


2.希尔排序

2.1什么是希尔排序

希尔排序是将待排序的数组元素 按下标的一定增量分组(gap) ,分成多个子序列,
然后对各个子序列进行直接插入排序算法排序;
然后依次缩减增量再进行排序,直到增量为1时,进行最后一次直接插入排序,排序结束。

2.2希尔排序不稳定的原因:

这个不稳定的原因还是相同的数据,但是这两个数据的前后顺序改变了。

我用*代表的是相同的两个数,出现的更靠后那个。

然后gap的距离不断减小,一直到升序排序后,6*一直就会再6的前面了,所以希尔排序也是不稳定的。

2.3希尔排序时间复杂度

增量序列的选择会极大地影响希尔排序的效率。 希尔排序时间复杂度非常难以分析,

它的平均复杂度界于 O(n) 到 O(n^2) 之间,普遍认为它最好的时间复杂度为 O(n^1.3)

希尔排序其实是插入排序的一个优化,而插入排序的时间复杂度是O(n^2),希尔排序的时间要小于插入排序,也可以这样理解。


3.堆排序

3.1啥是堆排序

堆排序有大堆排序和小堆排序两种堆排序方式,小堆排序就是让根节点是最小的,根节点必须小于左右子节点,但是不需要比较左右子节点的大小。只需要保证根节点小于子节点即可。大堆就是让根节点大于左右子节点即可。堆排序的底层是数组来实现的。

3.2堆排序不稳定的原因:

堆排序的根本是不是沿着根节点找叶子节点,并比较两者的值进行相关的交换。但是如果说用相同的两个值出现在一个堆中,就可能造成不稳定性。

3.3堆排序时间复杂度

这个我就不推导了,各位就记住他是O(nlogn)吧,推导一遍的意义不大,纯属浪费时间。


4.选择排序

4.1什么是选择排序

选择排序的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的后面。以此类推,直到全部待排序的数据元素排完。

4.2为啥选择排序不稳定

之所以它不稳定,还是因为重复出现的数据的顺序可能出现改变

有的兄弟可能看不懂是咋比较的,选择排序是选出最小值放在序列最前面,也就是5的位置存放的是最小值。所以挨个比较,然后找到5>1,所以交换5和1--->1 5* 5 7。所以这个排序变得不稳定了。

4.3选择排序的时间复杂度

对于选择排序来说,外层循环决定的是n个位置的归属权,所以要比较n-1次,对于内层循环,最坏的情况是逆序排列,那要比较n-1,n-2...1次,所以他的时间复杂度是O(n^2)


5.插入排序的稳定性示范

有的老铁该说,按你说的,那稳定排序也会这样子排列。我们来试一下稳定排序究竟会不会这么排。

我们用插入排序试一下。

5.1什么是插入排序

插入排序就是将无序数组最前面出现的几个数作为一个区间,后面的数如果在区间内,就直接排在区间里,如果大于或者小于这个区间就更新位区间的边界。然后继续插入。

5.2插入排序的稳定

就比如上面的5 7 6 7*,首先把5当作一个区间,然后插入7,5<7,把区间扩展成[5,7],然后插入6,6在区间呢。所以是[5,6,7],然后插入7*,这个7*和7相等,所以不往区间里面填了,而是把后面的7*作为新的边界处理,所以他是稳定的排序算法。

5.3插入排序的时间复杂度

对于插入排序来说,它的时间复杂度特别好计算,最坏的情况是不是逆序,所以n个数要比较n-1+n-2+n-3+...+2+1=n*(n-1)/2。 同理,它交换的次数也是n*(n-1)/2

所以他的时间复杂度是O(n^2)


6.不稳定性的总结:

综合三种不稳定排序的相关原因来说,都是几个相同的数据进行排序后,后出现的排在了前面,先出现的排在后面。相同的数据的出现次序可能会造成不稳定排序。
切记要注意这是可能会造成,不是一定会造成。

二、稳定排序复杂度分析

1.冒泡排序:

1.1什么是冒泡排序

冒泡排序就是 依次比较相邻两个数字,交换数字,直到最大的数字被排列到序列的最尾部。
它重复地走访过要排序的元素列,依次比较两个相邻的 元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

1.2冒泡排序和选择排序的区别

在上面我们介绍了一种选择排序,在这我们就不说它俩的相同点了,一说往后就更不好区分了。

区别:(这里我们默认的都是升序排序)

  • 选择排序是序列的最前端位置存放的是最小数据,然后让其他数据和这个最小数据比较,如果比最小数据还要小,就跟这个最小数据交换,必须保证序列最前端的是最小元素,找到最小元素后,在找第二小元素。直到完全排序完。

  • 冒泡排序是从头开始,相邻的的两个元素依次进行比较大小,较大的元素被交换的右边,然后这个较大的元素再和其右边的元素进行比较,直到最大元素被交换到序列的最右边。这时我们就在比较剩余的n-1个元素就行了。

  • 最简单的一句话就是选择排序进行单挑,冒泡排序进行车轮战。

1.3冒泡排序的复杂度

冒泡排序的 最差时间复杂度是:(n-1)*n/2 + (n-1)*n/2 = n^2 -n 忽略低次幂得到 O(n^2)

这是最差的情况,最好的情况是升序排序,只需要进行比较,不需要进行交换。所以是n个元素比较n-1次,时间复杂度是O(n)。这个是flag判断外层循环后,数据有没有发生交换,没交换说明原本数据是升序。

2.归并排序

将已有序的子序列 合并,得到完全有序的 序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为 二路归并。

归并操作,也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。

如 设有数列{6,202,100,301,38,8,1}

初始状态:6,202,100,301,38,8,1

第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;逆序次数:1

第二次归并后:{6,100,202,301},{1,8,38},比较次数:4; 逆序次数:1+2=3

第三次归并后:{1,6,8,38,100,202,301},比较次数:4; 逆序次数:4+3+3=10

总的比较次数为:3+4+4=11;

逆序数为:1+3+10=14.。

这里我没把数据以个体为单位而是两个进行比较。

最后一步为啥比较次数是4呢,首先是两个子序列首进行比较,6>1,所以1放进数组中,再拿1后面的数和6比较。6<8,把6放到数组中,比较100和8,再把8放到数组中,比较100和38,把38放到数组中,子序列2已经空了,此时我们可以直接把子序列1中剩余的数据直接放到数组里面就行了。

所以此次就比较了4次:6>1,6<8,100>8,100>38。

2.2归并排序的复杂度

归并排序总时间=分解时间+子序列排好序时间+合并时间

无论每个序列有多少数都是折中分解,所以分解时间是个常数,可以忽略不计。

所以归并排序总时间=子序列排好序时间+合并时间;

  • 第一次折中分解时间

假设这n个数排序的时间是T(n),那第一次折中分解的时间T(n)=2*T(n/2),到最后排序好合并时,只需要一个n个数的循环就可完事,所以时间复杂度是n.

T(n)=2*T(n/2)+n;
  • 再进行折中分解,此时有四个子序列了。

一个(n/2)序列排序时间=两个(n/4)的序列排序时间+两个(n/4)的序列的合并为一个(n/2)的序列时间T(n/2)=2*T(n/4)+n/2。

 通过化简T(n)=4*T(n/4)+2n
  • 第三次折中分解的时间

T(n/4)=2*T(n/8)+n/4
将T(n/4)带入到黄色公式中,
T(n)=4*(2*T(n/8)+n/4)+2n,简化后:T(n)=8*T(n/8)+3n

到最后分解成一个完全二叉树的形式。通过观察可得,合并时间的那个系数和层数有关,是层数-1.所以我们可以根据节点数n求出层数。n个节点的层数是log2n+1,

所以和并部分的时间是log2n+1-1=log2n.

  • 那么我们最后一层是不是可以这样表示

T(n)=n*T(1)+(log2n)*n
T(1)=0,那么T(n)=(log2n)*n
所以归并排序的时间复杂度为O(nlog2n)≈ O(nlogn)
我看了好多网上的资料,有的证明是O(nlog2n),有的是O(nlogn), 这里我们就统一一下用后者吧。

三、归纳总结:

算法名称

时间复杂度

算法稳定性

快速排序

O(nlogn)

不稳定

堆排序

O(nlogn)

不稳定

希尔排序

O(n^1.3)

不稳定

选择排序

O(n^2)

不稳定

插入排序

O(n^2)

稳定

冒泡排序

O(n^2)

稳定

归并排序

O(nlogn)

稳定

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

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

相关文章

详解最近公共祖先(LCA)

看本博客前建议先看一下ST算法解决BMQ问题详解一&#xff0c;LCA概念最近公共祖先(Lowest Common Ancestors, LCA)指有根树中距离两个节点最近的公共祖先。祖先指从当前节点到树根路径上的所有节点。u和v的公共祖先指一个节点既是u的祖先&#xff0c;又是v的祖先。u和v的最近公…

php网上书城|基于PHP实现网上书店商城藉项目

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

3分钟秒懂,最简单通俗易懂的spring bean 生命周期介绍与源码分析,附上demo完整源码

文章写作背景 最近突然身边很多小伙伴问我有没有spring bean生命周期的通俗移动的介绍 起初不太理解为什么&#xff0c;后来才想明白&#xff0c;哦对了&#xff0c;年底了&#xff0c;快开始跳槽季了&#xff0c;这不就是java八股文面试 的题目嘛&#xff0c;不得不说&#xf…

【5G RRC】Master Information Block (NR-MIB)

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

手把手教你分析 Linux 启动流程

下载 Linux 内核网址: https://www.kernel.org/ 常用 Linux 内核源码为 4.14、4.19、4.9、5.10、5.15、6.1 等版本,其中 4.14 版本源码压缩包大概 90+M,解压后 700+M,合计 61350 个文件。如此众多的文件,用 source insight 或者 VSCode 查看都会比较卡,所以可以采用在线…

计算机网络第四章

1.网络层主要任务是把分组从源端传到目的端&#xff0c;为分组交换网上的不同主机提供通信服务&#xff0c;网络层传输单位是数据报三个功能&#xff1a;路由选择与分组转发&#xff08;最佳路径&#xff09;异构网络互联拥塞控制数据交换方式三种交换方式&#xff1a;电路交换…

一动不动是王八?动态内存有话说

文章目录前言动态内存函数介绍mallocfreecallocrealloc柔性数组柔性数组特点柔性数组的优点方便内存释放提高我们的访问速度总结前言 一动不动是王八&#xff0c;出自2014年的春晚&#xff0c;小时候经常喜欢说这句话&#xff0c;那在我们C语言中&#xff0c;我们知道&#xf…

年度征文|一个业余电脑玩家的30年(1992-2022)

《论语为政》&#xff1a;“五十而知天命”。岁月真的是一把刀&#xff0c;一晃已过不惑之年&#xff0c;还有几天就要进入知非之年。不论知非还是知天命&#xff0c;反正是花甲将至而从心所欲了。年少时因某种不合机缘&#xff0c;错与IT界擦肩而过&#xff0c;每每想起就扼腕…

gradel学习+IDEA配置

Gradle的下载 Gradle下载地址如下 https://gradle.org/releases/ 我自己的下载的7.4.2 可以选择下载完整的压缩包&#xff0c;将压缩包解压到自己指定的目录中即可。 Gradle安装 1、配置系统变量 GRADLE_HOME 2、配置环境变量 %GRADLE_HOME%是获取变量名称为GRADLE_HOME的…

项目看板开发经验分享(一)——光伏绿色能源看板

今天新开一个系列&#xff0c;专门介绍近期工作中开发的几个比较酷炫的看板的开发思路与经验分享。第一节我们就来介绍下这个光伏绿色能源看板&#xff0c;整体浏览如下&#xff1a; 那就直接进入正题吧—— 0、可复用组件panel 在讲解各个模块之前&#xff0c;我们先来完成一…

Mybatis 框架下 SQL 注入攻击的 3 种方式

SQL注入漏洞作为WEB安全的最常见的漏洞之一&#xff0c;在java中随着预编译与各种ORM框架的使用&#xff0c;注入问题也越来越少。 新手代码审计者往往对Java Web应用的多个框架组合而心生畏惧&#xff0c;不知如何下手&#xff0c;希望通过Mybatis框架使用不当导致的SQL注入问…

Node.js学习笔记

Node.js学习笔记 浏览器的内核包括两部分核心&#xff1a;DOM渲染引擎、JavaScript解析引擎。脱离浏览器环境也可以运行JavaScript&#xff0c;只要有JavaScript引擎就可以。 Node.js是一个基于Chrome V8引擎的JavaScript运行环境。Node.js内置了Chrome的V8 引擎&#xff0c;…

SpringBoot项目部署

系列文章目录 Spring Boot[概述、功能、快速入门]_心态还需努力呀的博客-CSDN博客 Spring Boot读取配置文件内容的三种方式_心态还需努力呀的博客-CSDN博客 Spring Boot整合Junit_心态还需努力呀的博客-CSDN博客 Spring Boot自动配置--如何切换内置Web服务器_心态还需努力呀…

Open3D SOR滤波(Python版本)

文章目录一、简介二、实现代码三、实现效果参考资料一、简介 SOR滤波过程相对简单&#xff0c;其原理是通过查询点与邻域点集之间的距离统计判断来进行过滤离群点。假设一个点的邻近点集符合正太分布&#xff0c;因此我们可以通过计算出该点到它所有临近点的平均距离meanD和标准…

国内怎么体验openAI chatGPT

怎么体验openAI chatGPT 一&#xff0c;前提 1&#xff0c;先准备好一个gmai的邮箱&#xff0c;注册时要用 2&#xff0c;&#xff08;懂得都懂&#xff09; 3&#xff0c;ChatGPT&#xff1a;网址 二&#xff0c;开始注册 1,sign up&#xff0c;用Gmail注册&#xff0c;我…

洛谷P8942 Digital Fortress

题目大意 给定一个区间&#xff0c;构造一个单调不减的序列&#xff0c;使得其前缀异或和与后缀异或和均单调递减&#xff0c;判断这种序列是否存在并输出任意一种解。 思路 暴力 dfs 当然会 TLE,所以我们要仔细分析&#xff1a; ① 在什么情况下异或和能够单调不减&#x…

2023/1/15 JS-原型与原型链

1 什么是原型 原型是Javascript中的继承的基础&#xff0c;JavaScript的继承就是基于原型的继承。每一个JS对象都可以获得自己的原型&#xff0c;通过原型可以共享函数对象和实例对象之间的属性和方法。 原型的出现&#xff0c;就是为了解决 构造函数 的缺点&#xff1a; 每一…

HTB-Shoppy

HTB-Shoppy信息收集开机提权信息收集 22和80。 能扫描出来的东西很杂&#xff0c;但是admin和login可以重点关注。 访问其中之一&#xff0c;能发现是一个登陆界面。 对其进行简单的sql注入测试。输入admin’or11#会出现504超时&#xff0c;判断可能是因为有sql防御措施所致。…

SpringCloud Netflix复习之Zuul

文章目录写作背景Zuul是什么Zuul的核心功能上手实战SpringCloud中Zuul如何使用自定义过滤器配置全局Fallback降级Zuul请求头Ribbon等其他参数配置过滤敏感请求头参数配置开启Ribbon懒加载和Ribbon超时配置开启Hystrix超时配置(一般不配置没啥用)源码部分请求入口ZuulServlet注入…

C++入门--list

目录 list的介绍&#xff1a; list的构造&#xff1a; 遍历&#xff1a; reverse、sort、unique list的模拟实现&#xff1a; 反向迭代器&#xff1a; list与vector的比较&#xff1a; list的介绍&#xff1a; list是序列容器&#xff0c;允许在序列内的任何位置执行O(…