Java排序算法知多少
今天阿粉就来谈一下这个 Java 中的各种排序的算法,因为之前遇到了一个面试高级开发,结果竟然出了一个 九九乘法表的题,阿粉当时听完读者说的,瞬间就明白是什么意思了,这感觉有点忽悠人,但是实际上却是面试官想要考察你的排序算法的事了,也有可能是真的无聊。 排序算法
什么是排序算法,实际上这个没有太多的说法,意思表达清楚就可以了,所谓排序,就是一串记录,按照其中的某个或某些关键字的大小,递增或递减地排列起来的操作。
排序算法的种类可以说是比较的多样化了,对时间,对空间的效率,不同的排序算法的优缺点是不一样的,有些是用时间换空间的,有些是拿空间换时间的,今天阿粉就来一一列举一下。 冒泡排序
什么是冒泡排序呢?
冒泡排序就是依次比较相邻的两个数,将小数放在前面,大数放在后面。
就像一个泡泡,一个泡泡一样,直接往起漂。
冒泡排序就是依次比较相邻的两个数,将小数放在前面,大数放在后面。
实际上比较的过程就是这个样子的:
第一次比较:
首先比较第1个和第2个数,将小数放前面,大数放后面,然后比较第2个数和第3个数,小数放前面,大数放后面,然后一直比较到最后,这样,最大的一个数就放到了最后面了。
第二次比较:
首先比较第1个和第2个数,将小数放前面,大数放后面,然后比较到倒数第二个数,然后第二次比较结束,这样在最后一个位置的就是最大的,然后倒数第二个位置的是第二大的数。
然后一直这样往下执行,第三次就是来取第三个数,这样依次循环,这样说大家肯定都是能理解的,假设需要排序的序列的个数是n,则需要经过n-1轮,最终完成排序。在第一轮中,比较的次数是n-1次,之后每轮减少1次。
我们接下来使用代码来实现一下: public static void main(int[] a) { int temp; //需要比较n-1轮 for (int i = 0; i < a.length-1; i++) { //根据a.length-i-1,每轮需要比较的次数逐轮减少1次 for (int j = 0; j < a.length-i-1 ; j++) { //相邻数进行比较,符合条件进行替换 if (a[j] > a[j+1]) { temp = a[j]; a[j] = a[j+1]; a[j+1] = temp; } } } } 插入排序
插入排序的种类比较多 直接插入排序 二分插入排序 希尔排序
这些排序方式全都是属于插入式排序的,
我们先来看看直接插入排序:
比较的过程是这个样子的,数组的第二个数据开始往前比较,即一开始用第二个数和他前面的一个比较,如果 符合条件则让他们交换位置。
假如我们给定一个数组,我们要按照从小到大排序,数组为 [3,1,4,6,5,17,12,11] 这时候,第一步就是拿着 1 和 3 进行比较,如果 1 小于 3 ,这个时候,就把 1 和 3 换个位置,[1,3,4,6,5,17,12,11] .
接下来再用第三个数和第二个比较,符合则交换,但是此处还得继续往前比较 ,就是用 4 和 3 和 1 分别去比较,然后一直这么重复下去。直到把所有的数据都排列完之后,就得到了我们想要的结果,我们来写个代码看看是什么样子的。 public static void basal(int[] array) { // 从第二项开始 if (array == null || array.length < 2) { return; } for (int i = 1; i < array.length; i++) { int cur = array[i]; // cur 落地标识,防止待插入的数最小 boolean flag = false; // 倒序遍历,不断移位 for (int j = i - 1; j > -1; j--) { if (cur < array[j]) { array[j + 1] = array[j]; }else { array[j + 1] = cur; flag = true; break; } } if (!flag) { array[0] = cur; } } } }
既然我们之前都说了,插入排序的方法有很多种,那么我们也得说说其他的插入排序,然后在看看他们都有什么不同的地方,大家说对不对呢?
既然我们刚才都说了排序每次都要讲数组后移,但是我们之前的判断条件上却是可以优化出来的,这样优化优化的就衍生出来了其他的不同的插入排序,接下来我们就来看看这个二分查找插入排序。 二分查找法插入排序
优化直接插入排序的核心在于:快速定位当前数字待插入的位置。在一个有序数组中查找一个给定的值,最快的方法无疑是二分查找法,至少在阿粉的心中如果想到优化的时候肯定是第一时间选择的就是可不可以使用二分查找法呢?
我们先来看看代码实现,然后再看看他有什么缺点,为啥有很多人都不选择使用二分查找插入排序。 // 利用系统自带的二分查找法,定位插入位置 // 不稳定排序 public static void optimized(int[] array) { if (array == null || array.length < 2) { return; } for (int i = 1; i < array.length; i++) { int cur = array[i]; int[] sorted = Arrays.copyOf(array, i); int index = Arrays.binarySearch(sorted,cur); if (index < 0) { index = -(index + 1); } for (int j = i - 1; j > index - 1; j--) { array[j + 1] = array[j]; } array[index] = cur; } }
在这其中,阿粉使用了系统自带的Arrays,然后进行了二分查找插入排序,为什么这么用呢?在JDK中提供了 Arrays.binarySearch(),方法的入参需要将有序数组传递进去 来进行实现,为什么不用这种方法呢?
假如在排序之前,有两个数相等,但是在排序结束之后,它们两个有可能改变顺序这就是说明该排序算法具有不稳定性。这就是大家所说的稳定性。
既然都有这种不稳定的排序,那是不是就应该存在稳定的排序呢?对没错,就是有,那么什么是稳定的排序呢?对,大家没有想错,冒泡排序就是稳定排序,因为冒泡排序只在相邻元素大小不符合要求时才调换他们的位置,它并不改变相同元素之间的相对顺序, 因此它是稳定的排序算法。
既然我们刚才说了这个排序中还有希尔排序,我们再来看看希尔排序。 希尔排序
说实话,阿粉第一次知道这个排序的时候,就想说,是不是一个叫做希尔的人改进的,结果,发现还真是,希尔排序,又叫做((缩小增量排序),因 D.L.Shell 于 1959 年提出而得名,实际上应该叫做Shell"s Sort。
希尔排序是先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
实际上就相当于先进行了一个简单的分组,将待排序数组按照步长gap进行分组,然后将每组的元素利用直接插入排序的方法进行排序;每次再将gap折半减小,循环上述操作;当gap=1时,利用直接插入,完成排序。
代码实现是这个样子的 public static void sort(int[] a) { int length = a.length; int h = 1; while (h < length / 3) h = 3 * h + 1; for (; h >= 1; h /= 3) { for (int i = 0; i < a.length - h; i += h) { for (int j = i + h; j > 0; j -= h) { if (a[j] < a[j - h]) { int temp = a[j]; a[j] = a[j - h]; a[j - h] = temp; } } } } } 选择排序
选择排序(Selection sort)是一种简单直观的排序算法。
这个就比较简单了,为什么这么说,是因为他就是直接从未排序的序列中去找最小或者最大的元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
实际上和冒泡排序在想法上有一丢丢的相似,但是就是不一样。
我们看看代码是否实现: public static void sort(int[] a) { for (int i = 0; i < a.length; i++) { int min = i; //选出之后待排序中值最小的位置 for (int j = i + 1; j < a.length; j++) { if (a[j] < a[min]) { min = j; } } //最小值不等于当前值时进行交换 if (min != i) { int temp = a[i]; a[i] = a[min]; a[min] = temp; } } }
既然阿粉都给大家列出了这几种排序,那么我们又回到一个问题上来了,排序这么多,怎么选择,为什么选择,这就又涉及到了时间复杂度和空间复杂度上面了,要么用空间换时间,要么用时间换空间。 总结
冒泡排序
平均时间复杂度 最好情况 最坏情况 空间复杂度 O(n²) O(n) O(n²) O(1)
直接插入排序
平均时间复杂度 最好情况 最坏情况 空间复杂度 O(n²) O(n²) O(n²) O(1)
二分查找排序
平均时间复杂度 最好情况 最坏情况 空间复杂度 O(n²) O(n²) O(n²) O(1)
希尔排序
平均时间复杂度 最好情况 最坏情况 空间复杂度 O(nlog2 n) O(nlog2 n) O(nlog2 n) O(1)
选择排序
平均时间复杂度 最好情况 最坏情况 空间复杂度 O(n²) O(n²) O(n²) O(1)
今天的排序就说到这里了,你学会了么?
充电宝日本PSE认证测试项目有哪些?移动电源出口日本需要获得PSE认证才能在市场上销售,且移动电源的标准是跟电池同标准的,周期4周哦,如果您有移动电源产品,电池产品要销往日本的,请尽早把PSE认证申请办理了,否则无法
赚钱项目实操截拳道之截流术简单的来说,截拳道经历三个阶段模仿糅合开创成长也是分阶段进行的,人在每一个阶段都会有不同的题目,克服了一个,迎来另一个,螺旋式上升,盘旋着进步。所有的大boss都是从小喽啰养成的,
电竞必备听声辨位雷柏(Rapoo)VH610游戏耳机前言随着电竞游戏的火热,越来越多的电竞外设开始融入普通的家庭,好的游戏外设不仅提高游戏体验还可以更好的应用于日常使用中,就算不玩游戏,也可以通过游戏外设的高性能来提高日常生活中的操
格斗必备街机之王莱仕达专业电竞游戏摇杆PXNX9前言街机是80后90后必不可少的童年回忆。曾几何时,在那个相对匮乏的年代,不管是物质生活还是精神文化生活都相对比较贫乏。童年生活中没有平板,手机,电脑等高科技智能设备,玩遍了弹珠,
畅快游戏竞技必备北通阿修罗3手柄前言随着赛博朋克2077的发售,主机党严重受挫,因为主机的硬件配置是固定的,无法替代和更换,只能让厂家根据主机的硬件来优化性能,而今年的赛博朋克2077热度相当高,不管是主机还是P
割草依旧无双难寻Switch战国无双5游戏体验前言从PS2的时代第一次接触到无双系列就欲罢不能,依稀还记得那是高一的时候,朋友约我去一个黑游戏厅,门前是卖数码盗版光碟,家后院房间里就是PS游戏厅,三块钱一个小时可以随意选碟子,
全球公认的3名天才黑客,美国FBI不抓他们,还要请他们帮忙第3名乔纳森詹姆斯16岁时因入侵美国国家航空航天局电脑系统被捕,成为世界上第一个因黑客行为而被捕的未成年人,同年,他与FBI展开合作,找出了梅丽莎病毒的发布者,次年,又协助FBI找
青创助力,文创绽放青创营文创专场投融资路演活动成功举办城市是文化的载体,文化是城市的灵魂。8月26日,由共青团东莞市长安镇委员会东莞市人力资源和社会保障局长安分局主办,中青创投与东莞市长安镇青年企业
讯飞翻译笔S11,更多功能,让孩子学习无忧的词典笔近几年来,作为提高孩子学习效率的一款工具,电子词典笔已经摆上了越来越多孩子的书桌。不过要说最值得购买的词典笔产品,那还得是讯飞翻译笔S11。讯飞翻译笔S11之所以值得信赖,就是因为
美国CPSC发布16CFR第1107和1112部分中标准的最终法规美国CPSC发布16CFR第1107和1112部分中标准的最终法规2021年5月3日,美国消费品安全委员会(CPSC)公布了直接最终法规,以修订16CFR第1107和1112部分。
美国FDA验厂咨询辅导的费用和周期美国FDA验厂咨询辅导的费用和周期FDA每年会对全球的医疗器械制造商进行抽样审查,作为其进行售后市场监管的主要途径之一。所有的审查都会由美国FDA的工作人员进行,不论这些人是什么族