无论是日后面试还是笔试的,排序在数据结构与算法中有着举足轻重的地位,所以还是决定把数据结构这个专题好好写写,多研究研究!今天和大家一起学习交换类排序——冒泡和快排详解!
在排序中,冒泡和快排是考察最多的了,当然在实行上面冒泡要相比快排简单很多。理解起来也算得上是最简单的排序算法,而快排的话很多面试笔试都是要求手撕的,所以重要性不言而喻!当然,对于排序算法我当初首次接触学习的时候只是萌萌懂懂的,只是大概了解,死记了模板,能将快排手写出来,刷题用。后来我发现我太傻吊了,,java中明明有Arrays.sort()这个api可以直接调用我为啥要憨呼呼的手写?多个条件排序重写下comparator接口就OK为啥还要憨呼呼的手写?。。。自此,就踏上了不手写快排的不归路。。。
后来,渐渐的,这个排序思想用的少,被我成功的遗忘。。现如今,被我重新拾起,深入理解下,防止哪一天又那个大佬让我手撕下不会就尴尬了哈哈,把学习过程分享给大家!
冒泡排序,又称起泡排序。他是一种基于交换的排序典型,也是快排思想的基础。对于冒泡排序名字的由来,百度百科这么说:
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
当然,冒泡排序是一种稳定排序算法,时间复杂度位O(n^2^).基本思想是:从前往后把大元素往后调(或者从后向前把小元素往前调)。
具体思想为(把大元素往后调):
拿个例子来说,比如2,8,9,3,7,6,12,4这个序列的冒泡排序来说。会有多趟(7)排序,每一趟要执行多(8-k)次。
对于它的第一趟排序来说是这样的:
而多次排序每次的结果是这样的:
它的动态执行顺序为:
在具体实现的时候,要分清是从小到大还是从大到小,还有次数也要注意,谨防越界!
至于冒泡排序的关键代码为:
private static void maopaosort(int[] a) { // TODO Auto-generated method stub for(int i=a.length-1;i>=0;i--) { for(int j=0;ja[j+1]) { int team=a[j]; a[j]=a[j+1]; a[j+1]=team; } } } }
快速排序是对冒泡排序的一种改进,采用递归分治的方法进行求解。而快排相比冒泡是一种不稳定排序,时间复杂度最坏是O(n^2^),平均时间复杂度为O(nlogn),最好情况的时间复杂度为O(nlogn)。
对于快排来说,基本思想是这样的
快排需要将序列变成两个部分,就是序列左边全部小于一个数,序列右面全部大于一个数,然后利用递归的思想再将左序列当成一个完整的序列再进行排序,同样把序列的右侧也当成一个完整的序列进行排序。
其中这个数在这个序列中是可以随机取的,可以取最左边,可以取最右边,当然也可以取随机数。但是通常我们取最左边的那个数。当然,为了实现这个目标,实现方式可能不一样,但是我这里采取的是大众常规的方式和方法。!
这里的一个难题就是如何处理将比第一个数K小的全部放左面,把比K大的全部放右面!如果没有什么技巧,直接硬性往里面塞,你肯定要一个额外存储空间先把整个先存了。然后遍历比较然后放入目标区域。当然这样太浪费空间内存了。我们为了节省计算机资源,采取这样的方法:
对于一个序列的2,8,3,7,6,9,4,12来说,它的执行过程图解大致是这样的:
1 . 首先2是最小的,采用递归分治时候左侧相当于为空,只需要把右侧再进行排序。
2 .对于右侧序列来说,先用K储存a[low]=8我们先从右侧找到第一个小与8的数字4。
3 .我们将它放到low位置替换,然后从low位置向右找到第一个大于k=8的再同样放到右侧。我们找到9,把9赋值给high位置。
4 .重复上面步骤直到high
5 .就这样重复下去,直到整个序列有序即可!
在书写代码的时候,要注意一些顺序,防止数组越界情况,可以写好debug一遍其实就很好理解了!当写代码遇到错误时候,不要急着就去找正确答案,能有时间自己发现错误,可以借助断点查看程序执行流程,这样对自己的收益是最大的!
至于快排的代码,是这样的:
private static void quicksort(int [] a,int left,int right) { int low=left; int high=right; //下面两句的顺序一定不能混,否则会产生数组越界!!!very important!!! if(low>high)//作为判断是否截止条件 return; int k=a[low];//额外空间k,取最左侧的一个作为衡量,最后要求左侧都比它小,右侧都比它大。 while(low=k)//右侧找到第一个小于k的停止 { high--; } //这样就找到第一个比它小的了 a[low]=a[high];//放到low位置 while(low
对于完整的代码,为
package 八大排序;import java.util.Arrays;public class 交换类排序 { public static void main(String[] args) { int a[]= {2,8,9,3,7,6,12,4}; maopaosort(a); System.out.println(Arrays.toString(a)); int b[]= {2,8,9,3,7,6,12,4}; quicksort(b, 0, b.length-1); System.out.println(Arrays.toString(b)); } private static void maopaosort(int[] a) { // TODO Auto-generated method stub for(int i=a.length-1;i>=0;i--) { for(int j=0;ja[j+1]) { int team=a[j]; a[j]=a[j+1]; a[j+1]=team; } } } } private static void quicksort(int [] a,int left,int right) { int low=left; int high=right; //下面两句的顺序一定不能混,否则会产生数组越界!!!very important!!! if(low>high) return; int k=a[low];//取最左侧的一个作为衡量,最后要求左侧都比它小,右侧都比它大。 while(low=k) { high--; } //这样就找到第一个比它小的了 a[low]=a[high]; while(low
运行结果:
好了这个交换类排序就总结到这里了。总之,冒泡是很基础和容易,但是要注意这种简单排序所属的范畴(交换类)要和插入类等做好区分;而快排板子很好记,深入理解需要点时间消化吧。一次不行再来第二次,不行再来第三次,。。。
当然,如果感觉不错或者对你有所帮助,欢迎点赞收藏转发哈!如果感觉有问题或者纰漏还请指正哈!当然,笔者长期致力于<>这个专栏的更新和维护,欢迎大家关注一波哈!
最后,欢迎关注笔者微信公众号(bigsai),头条号(一直码农一直爽)!