Java基础数据结构之排序

news2024/11/18 10:44:39

一.排序

1.什么是稳定性

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持
不变,即在原序列中, r[i]=r[j] ,且 r[i] r[j] 之前,而在排序后的序列中, r[i] 仍在 r[j] 之前,则称这种排序算法是稳
定的;否则称为不稳定的。

2.分类

内部排序 :数据元素全部放在内存中的排序。
外部排序 :数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。(实际上就是数据再磁盘上存储)。

二.插入排序

1.直接插入排序

原理:当插入第i个数时,前面i-1个数据已经排好序了。只要用第i个数据和第i-1,i-2,i-3个数据依次进行比较,找到合适的位置插入,后面的数据一次后移即可

例如1,3,2,24,35,11 从大到小排,从第二个数开始定义一个临时变量tmp存放要排的数据3,此时1下标就是空的,定义一个i表示要进行比较的数的下标,此时i=0,3和1比,3大,所以把1放到1下标,i向前走发现i<0了,所以i就不向前走了,把tmp的值就放到i下标;假设11以前都排好了,即35,24,3,2,1,11,现在排11,tmp=11,初始i=4,tmp与4下标的数比较,11比1大,所以1放到5下标,i再向前走,11比2大,所以2放到4下标(即i-1下标),i再向前走,11比3大,所以3放到3下标(即i-1下标),i再向前走,24比11小,所以把11也就是tmp的值放到2下标(即i-1下标)。

代码如下

总结

1.时间复杂度:O(N^2);因为比较次数是依次递增,即1+2+3+4+……+(n-1).

2.空间复杂度:O(1);因为该代码使用的变量是常数个。

3.稳定性:稳定的

4.元素集合越接近有序,需要比较的次数就越少,时间效率就越高。比如从小到大排序1,2,3,4,5,已经有序了,只需遍历到每个元素即可,不需要回退,此时时间复杂度为O(N)。

5.适用于待排序序列已经基本接近有序

2.希尔排序(直接插入排序的优化)

希尔排序法又称为缩小增量排序法,把一组数分为若干组,每组进行直接插入排序

例如下图:

第一趟分为五组,即gap组,每组俩个元素,这俩个元素之间的距离就是gap,即5;让i=5,即i=gap,指向4,让j=i-gap,即0,j下标和i下标的值进行比较交换,然后j-=gap,但这样j就成了负数了,所以这一组比较完了,i++;i=6,j=i-gap=1,再比较,再交换……
第二趟分为俩组,每组五个元素,每个元素之间的距离为gap,即2,让i=gap即2,指向数据1,让j=i-gap,即0,比较,交换;i++(注意不是i+=gap,因为这样会导致跳过一组)
代码如下:
总结

1.时间复杂度:尚未有明确的规定,可以是n^1.3~n^1.6,也可以是n^1.25~1.6*n^1.25。

2.空间复杂度:O(1)。因为一直是在原数组上进行操作,没有额外开辟空间

3.稳定性:不稳定,原因是存在不相邻记录的交换。比如1,5,3,3,4,6,分成俩组进行从小到大排序,第一组是1,3,4,不用交换,第二组是5,3,6,需要交换变成3,5,6,这就导致第二个3跑到了第一个3的前面

三.选择排序

1.直接选择排序

定义一个i,从0下标开始遍历数组;再定义一个minindex,初始值为i,从i+1下标开始到n-1,每次将该下标的值与minindex下标的值进行比较,如果小于minindex下标的值,就将minindex更新为当前下标,最后将minindex与i下标的值进行交换,i++,到最后,该数组就是从小到大排序。代码如下:

总结

1.时间复杂度:O(N^2)

2.空间复杂度:O(1)

3.稳定性:不稳定,比如5,8,5,1,7要从小到大排序,我们知道,第一趟结束,5会和1进行交换,这是第一个5就到了第二个5之后,所以不稳定。

4.缺点:对于已经有序的数组,它还是会无脑的遍历从i到n-1的每一个数据,导致无论是最好情况下还是最坏情况下,都是O(N^2)。

2.双向选择排序

定义maxindex和minindex,定义left=0,right=arr.length-1,初始maxindex和minindex都等于left,然后遍历left到right下标的值,更新maxindex和minindex,最后将left下标与minindex下标的值进行交换,将right下标与maxindex下标的值进行交换,然后left++,right--。

代码如下:

但注意,这段代码有问题,如果maxindex就是left,那么mindex与left交换之后,maxindex指向的就是最小值了,直接让maxindex与right交换就会出问题,所以进行如下改进:

总结

1.时间复杂度:O(N^2)

2.空间复杂度:O(1)

3.稳定性:不稳定

3.堆排序

排升序建立大堆,排降序建立小堆。以升序为例:定义一个end,初始指向arr.length-1,将大根堆的0下标元素与end指向的元素交换,此时end下标的元素就是有序的,再将0下标元素进行向下调整(范围是0~end);然后end--,再与0下标的值进行交换,再向下调整……

代码如下:

总结

1.时间复杂度:O(N*log2N)。因为向下建堆的时间复杂度为O(N),而从0到end进行向下调整的全过程的时间复杂度为O(N*log2N),所以O(N)可以忽略不记,只记O(N*log2N)

2.空间复杂度:O(1)。

3.稳定性:不稳定。

四.交换排序

1.冒泡排序

代码如下:

优化:

总结

1.时间复杂度:O(N^2)。

2.空间复杂度:O(1)。

3.稳定性:稳定。

2.快速排序

其基本思想为: 任取待排序元素序列中的某元 素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有 元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止
将区间按照基准值划分为左右两半部分的方式有Hoare版,挖坑法,前后指针法,下面依次介绍:

(1).Hoare版

以0下标的数为基准值,初始化left=1,right=arr.length-1,right先向左移动,找到比0下标小的数就停止,然后left向右移动,找到比0下标的值大的数就停止,之后left和right下标的值进行交换,然后再让right移动,left移动,重复上述过程,直到left和right相遇时,设相遇时的下标为flag,就将0下标的值与flag下标的值进行交换;然后进行递归,就是让flag的左边和右边都进行Hoare版的快速排序。代码如下:

注意:必须先让right找小的,因为最终是left与right相遇的地方即flag和0下标交换,此时原来0下标的值就在原来flag下标的值的右边,如果先让left找大数,就可能会导致把比基准值大的数放到了基准值的左边,而先让right找就没问题

(2).挖坑法

先将第一个数据存放在临时变量key中,形成一个坑位,然后right向左走,找到比key小的数,拿起来放到0下标处,此时的坑位转移到了right下标,然后让left向右走,找到比key大的数,将它拿起来放到right下标,此时坑位转移到了left处,依此类推,直到left与right相遇后将key的值放到相遇处,并以相遇处为分割线进行左右递归,代码如下:

注意,必须是arr[right]>=key,等号不可以忽略,否则就会死循环。比如6,1,3,4,7,6,left=0,right=5,6大于6吗?不大于,所以第一个while进不去,所以将right的值给到left下标,即6和6进行交换,然后进行第二个while的判断,又进不去,所以又交换……一直这样死循环。

(3).前后指针法

定义key指向0下标,初始化prev指向0,初始化cur指向0,cur往后走找到一共比key指向的数据小的值时停止,然后prev先++,如果prev和cur指向的不是同一个数,就让prev指向的数与cur指向的数交换,然后cur再去找下一个比key小的数,直到cur走到头后,让key下标的值与prev下标的值进行交换,返回prev,再以prev为基准,左右向这样去递归。代码如下:

总结

1.时间复杂度:O(N*log2N)。这可以说是最好情况下是O(N*log2N),即每一次找到的flag都是在这组数据的中央,第一层是一整组,共n个数据,都要遍历到;第二层是从中央的flag分开成俩组,每组n/2个数据,都要遍历到……一共有log2n层,每层都是遍历到n个数据,所以是O(N*log2N)

而最坏情况下是O(N^2),即每次找到的flag都是第一个数据,导致没有左边,只有右边,所以这种情况下是:第一层遍历n个数据进行比较,第二层是n-1个数据,第三层是n-2个数据……一共是n层。

2.空间复杂度:O(log2N)。这主要与函数的递归调用有关。实际上,O(log2N)是最好情况下,也就是每次找到的基准值的下标都是中间值,所以先对基准值的左边进行递推,一共log2n层,所以在栈上开辟了log2n个空间,然后回退,直到把左边递归完,再此同时把这log2n个空间回收,然后对右边进行递归,又是开辟log2n个空间……总的来说就是O(log2N)

最坏情况下就是基准值一直是第一个,导致一共要开辟n个空间,所以是O(N)。

3.稳定性:不稳定,比如6,7,3,4,5,10,3,第一次就是7和最后一个3进行交换,导致俩个3的位置发生了改变

4.缺点:当数组数据过多,递归次数过大时,可能会造成栈溢出

3.快速排序的优化

出发点:减少递归的次数,也就是尽量让数组变成一棵完全二叉树,让基准值尽量为中间值

(1).三数取中法选基准

定义left,right,再定义mid=(left+right)/2,选取三个下标对应的数中的中位数,将其与left下标的数进行交换,然后再用上面的三个方法返回flag下标,再去递归,这样可以减少基准值总是在头或尾的情况。代码如下:

(2).递归到小的子区间时,可以用直接插入排序

就是说,越往下递归,数据越有序,选择直接插入排序的时间效率就会越高,所以可以在三数取中法的基础上再如下优化:

(3).非递归的快速排序

用到了栈。首先定义start和end,先找到基准值的下标,然后将基准值左半部分的开头和结尾的下标存到栈中,再将基准值右半部分的开头和结尾的下标存到栈中,注意,如果基准值左侧不够俩个元素,就不能将左侧的开头和结尾的下标存到栈中,右边也同理(如果flag-1>start,就说明左边够俩个元素,如果flag+1小于end,就说明右边够俩个元素)。然后弹出一个数给到end,再弹出一共数给到start,再去找基准值,以此进行循环,而不是递归,直到栈为空。

五.归并排序

归并排序( MERGE-SORT )是建立在归并操作上的一种有效的排序算法 , 该算法是采用分治法( Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

1.递归实现归并排序

对于一个数组1,6,5,2,3,7,4,9,先将它分裂,分成左右俩半,再将左边分成左右俩半,再将右边分成左右俩半,直到每组只有一个数据,然后让每组先在内部进行排序,然后左右俩组再进行排序(此时就是俩个有序数组的排序,叫做二路归并)。

代码如下:

起初start=0,end=arr.length-1,然后进行分裂,最后回归后进行二路归并。二路归并代码如下:

对于已经有序的俩个数组,比如:1,4,6,7和2,3,5,9,定义s1,e1,s2,e2,比较s1,s2对应的数,如果s1小,就将s1对应的数拷贝到tmp数组,然后s1++,反之s2++。直到s1>e1或s2>e2时结束,此时如果s1<=e1,说明左面的数还没有完全拷贝到tmp中,因为已经有序,所以直接拷贝即可,反之操作s2

总结

1.时间复杂度:O(Nlog2N)。这个数组最终被拆成了一棵完全二叉树,所以一共经历了log2N层,在回退进行二路归并时,每层都遍历了n个元素,所以是O(log2N)。

2.空间复杂度:O(log2N)。一共log2N层,就是开辟了log2N个空间后才开始回收空间去递归另一边。

3.稳定性:稳定

2.非递归实现归并排序

先一个一个有序,然后俩个俩个有序,然后四个四个有序……

代码如下:

比如数组1,4,2,3,6,5,3,2,首先每组一个数据,已经有序,所以从每组两个数据开始,14,23,65,32,left=i,right=i+gap-1,二路归并后得到14,23,56,23,然后变成每组四个数,即1423,5623,进行二路归并排序(第一路是left到mid,第二路是mid+1到right),得到1234,2356,最后gap=8,再排序。但这样的代码有错误,对于数组长度不是2^n的就不适用,比如1,4,2,6,5,3,共6个数,gap=2时变成14,26,35,然后当gap=4时,i初始为0,i+=gap得到4,那么第二组的left=4,right=7超了,所以right变成5,同理mid也是5,排完变成1246,35,最后按理说应该再对整体排序,但gap=8超过数组长度了,所以最后一组排序没有正常进行,所以这个代码不适用

代码修改:真正实现显性的两个有序数组的合并,即每次i+=gap*2,直接俩组俩组的操作

对于数组3,1,2,5,7,1,首先gap=1,分成每组一个,已经有序,然后俩组俩组进行二路归并排序,首先是第1,2组,left=0,mid=0,right=1,……得到13,25,17,然后gap=2,即每组俩个数,两组进行归并排序,前俩组得到1235,后面i=4时,left=4,mid=5,right=8,right超了,所以变成right=5,再去归并排序,此时的俩个有序数组是17和空数组;最后gap=4,i=0时,left=0,mid=3,right=7超了,所以right=5,此时的俩个有序数组是1235和17,再去二路归并排序。这样就能全部排好序了

我们不难发现,改进后的代码中left和mid恰好是第一个有序数组的首尾,mid+1和right正好是第二个有序数组的首尾,而且第二个有序数组的长度可以小于gap甚至为0。而之前的代码可能排序不完善

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

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

相关文章

Oladance、韶音、南卡开放式耳机,究竟谁在性能与音质上达到巅峰?

​开放式耳机作为新型耳机&#xff0c;以其开放性设计、舒适性和音质表现受到用户青睐。然而&#xff0c;随着市场的繁荣&#xff0c;一些品牌为谋取暴利可能采用劣质材料、不合规的工艺标准制作产品&#xff0c;导致耳机做工质量差&#xff0c;音质差。作为资深音频测评师&…

C++入门语法———命名空间,缺省参数,重载函数

文章目录 一.命名空间1.存在意义2.语法使用1.定义命名空间2.使用命名空间的三种方式 二.缺省参数1.全缺省参数2.半缺省参数 三.重载函数1.定义2.重载原理———名字修饰 一.命名空间 1.存在意义 C命名空间的主要意义是为了避免命名冲突&#xff0c;尤其是在大型项目中可能存在…

图卷积网络(GCN)

本文主要分为两部分&#xff0c;第一部分介绍什么是GCN&#xff0c;第二部分将进行详细的数学推导。 一、什么是GCN 1、GCN 概述 本文讲的GCN 来源于论文&#xff1a;SEMI-SUPERVISED CLASSIFICATION WITH GRAPH CONVOLUTIONAL NETWORKS&#xff0c;这是在GCN领域最经典的论文…

【Java并发】聊聊活锁

在并发编程中&#xff0c;为了保证数据安全性&#xff0c;所以使用锁机制&#xff0c;syn lock cas 等方式保证&#xff0c;但是也从一定程度降低了性能。而除了这个方面&#xff0c;还引入了锁竞争&#xff0c;比如死锁、活锁。 【Java并发】聊聊死锁 避免死锁&#xff1a;避…

动静态库的理解、制作、使用。

一.动静态库的理解。 1.什么是库&#xff1f; 代码是无穷无尽的&#xff0c;当程序猿在写一些项目时&#xff0c;未必所有代码亲历亲为&#xff0c;他们可以在网上寻找大佬写过的一些有关需求的代码&#xff0c;这些代码可以让他们拿过来直接使用&#xff0c;而省去了许多精力…

Linux中文件属性的获取(stat、chmod、Istat、fstat函数的使用)

修改文件权限 函数如下&#xff1a; chmod/fchmod函数用来修改文件的访问权限: #include <sys/stat.h> int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode); 成功时返回0&#xff1b;出错时返回EOF 注意&#xff1a;在vmware和windows共享的文…

K8S的HPA

horiztal Pod Autoscaling&#xff1a;pod的水平自动伸缩&#xff0c;这是k8s自带的模块&#xff0c;它是根据Pod占用cpu比率到达一定的阀值&#xff0c;会触发伸缩机制 Replication controller 副本控制器&#xff1a;控制pod的副本数 Deployment controller 节点控制器&…

c++ mysql数据库编程(linux系统)

ubuntu下mysql数据库的安装 ubuntu安装mysql&#xff08;图文详解&#xff09;-CSDN博客https://blog.csdn.net/qq_58158950/article/details/135667062?spm1001.2014.3001.5501 项目目录结构 数据库及表结构 public.h //打印错误信息 #ifndef PUBLIC_h #define PUBLIC_H…

BIGVGAN: A UNIVERSAL NEURAL VOCODER WITHLARGE-SCALE TRAINING——TTS论文阅读

笔记地址&#xff1a;https://flowus.cn/share/a16a61b3-fcd0-4e0e-be5a-22ba641c6792 【FlowUs 息流】Bigvgan 论文地址&#xff1a; BigVGAN: A Universal Neural Vocoder with Large-Scale Training Abstract 背景&#xff1a; 最近基于生成对抗网络&#xff08;GAN&am…

JavaScript 执行上下文与作用域

执行上下文与作用域 ​ 执行上下文的概念在 JavaScript 中是颇为重要的。变量或函数的上下文决定了它们可以访问哪些数据&#xff0c;以及它们的行为。每个上下文都有一个关联的变量对象&#xff08;variable object&#xff09;&#xff0c; 而这个上下文中定义的所有变量和函…

Vue基础–列表渲染-key的原理

一、v-for列表渲染 1.列表渲染 在真实开发中&#xff0c;我们往往会从服务器拿到一组数据&#xff0c;并且需要对其进行渲染。 这个时候我们可以使用v-for来完成&#xff1b; v-for类似于JavaScript的for循环&#xff0c;可以用于遍历一组数据&#xff1b; 2.v-for基本使用…

QT发送request请求

时间记录&#xff1a;2024/1/23 一、使用步骤 &#xff08;1&#xff09;pro文件中添加network模块 &#xff08;2&#xff09;创建QNetworkAccessManager网络管理类对象 &#xff08;3&#xff09;创建QNetworkRequest网络请求对象&#xff0c;使用setUrl方法设置请求url&am…

142基于matlab的移动力过简支梁程序

基于matlab的移动力过简支梁程序&#xff0c;算法采用newmark-belta法&#xff0c;输出简支梁&#xff0c;求解静力位移&#xff0c;自振特性&#xff0c;动力特性。可调节简支梁参数。程序已调通&#xff0c;可直接运行。 142 matlab简支梁自振特性 (xiaohongshu.com)

java集合ArrayList和HashSet的fail-fast与fail-safe以及ConcurrentModificationException

在 java 的集合工具类中&#xff0c;例如对 ArrayList 或者 HashSet 进行删除元素后再遍历元素时&#xff0c;会抛出 ConcurrentModificationException 异常。 fail-fast ArrayList public class TestList {public static void main(String[] args) {ArrayList<Integer>…

02-echarts如何画轴心轨迹图

echarts如何画轴心轨迹图 一、创建图表盒子1、创建盒子2、定义数据1、定义x&#xff0c;y点数据2、集合x,y点数据3、组件使用1、引入2、编写获取半径方法2、编写获取角度方法3、转换角度&#xff0c;半径数组3、初始化图表方法4、调用方法 二、全部代码1、dataXY.js2、组件中代…

Qt 多次绘图

使用Qt 的时候发现&#xff1a; 背景&#xff1a;自己定义一个类&#xff0c;把它和某个ui文件绑定。(类似 Qt creator 默认创建的工程&#xff09;问题&#xff1a;当鼠标在窗口内单击的时候会触发2次绘图。&#xff1f;难道不应该是一次吗&#xff1f; 于是开始了如下的测试…

SQL Server多数据表之间的数据查询和分组查询

文章目录 一、多数据表之间的数据查询1.1内连接查询&#xff08;Inner join&#xff09;1.2 左外连接 (LEFT JOIN):1.3右外连接 (RIGHT JOIN):1.4. 全外连接 (FULL OUTER JOIN):1.5 交叉连接 (CROSS JOIN):1.6 自连接 (SELF JOIN):1.7 子查询: 二、分组查询2.1 分组查询2.2 查询…

ai伪原创生成器app,一键生成原创文章

近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;AI伪原创生成器App已经成为了许多写手和创作者们的新宠。这款AI伪原创生成器App以其一键生成原创文章的快速便捷性&#xff0c;正在引起广泛的关注和使用。下面跟随小编一起来了解下吧&#xff01; 随着互联网的普及&…

两千字讲明白java中instanceof关键字的使用!

写在开头 在过往的内容中&#xff0c;我们讲了不少的Java关键字&#xff0c;比如final、static、this、super等等&#xff0c;Java中的关键字非常之多&#xff0c;下图是整理的关键字集合 而我们今天要学习的就是其中的instanceof关键字&#xff01; instanceof的定义 inst…

共享wifi项目到底能不能做?

如今&#xff0c;互联网已经渗透到我们生活的方方面面&#xff0c;人们对WiFi的需求越来越大&#xff0c;已经成为人们不可或缺的一部分。在这样的背景下&#xff0c;共享WiFi项目应运而生&#xff0c;作为近年来兴起的创业选择&#xff0c;成为了越来越多创业者追逐的热门项目…