程序员必备的八大排序算法
一、冒泡排序
这个排序应该是大部分程序员刚学习代码接触的第一个排序算法,它的原理也很简单,相邻的元素进行比较,满足条件就进行交换,总共需要遍历n轮。
时间复杂度O(N^2)
空间复杂度O(1)
到n轮进行完之后,整体就会有序。
public staic void bubbleSort(int arr[]){for(int i=0;i<arr.length;i++){for(int j=0;j<arr.length-i-1;j++){int temp=0;if(arr[j]>arr[j+1]){ //满足条件就交换temp=arr[j];arr[j]=arr[j+1];arr[j+1]=temp;}}}
}
二、选择排序
选择排序其实和冒泡排序一样都需要进行n轮的遍历,只不过不同于冒泡排序的是选择排序条件成立过后不是直接交换,而是对这个元素进行标记。
原理:对数组中的需要比较的第一个元素进行标记,然后进行遍历比较,后续元素满足条件就标记到这个元素上,直到遍历元素被遍历完,将被标记的元素和第一个元素进行交换。
时间复杂度O(N^2)
空间复杂度O(1)
到n轮进行完之后,整体就会有序。
public static void selectionSort(int[] arr){for (int i=0;i<arr.length;i++){int minIndex=i;//标记元素for (int j=i;j<arr.length;j++){minIndex=arr[minIndex]<arr[j]?minIndex:j;//满足条件就切换标记元素}int temp=arr[i];arr[i]=arr[minIndex];arr[minIndex]=temp;}}
三、插入排序
原理:从数组中的一个位置往前看,相邻的两个元素如果满足排序要求的条件,就直接进行下一轮的遍历检查,如果不满足,就与前一个位置的元素进行交换,然后继续往前看,直到这个元0素之前所有元素都满足排序所要求的条件再进行下一轮检查。
某些情况可能比选择和冒泡排序时间复杂度更优,可以认为是时间复杂度O(N^2)最好的一种排序。
时间复杂度O(N^2)
空间复杂度O(1)
到n轮进行完之后,整体就会有序。
public static void insertionSort(int[] arr){for (int i=0;i<arr.length;i++){for (int j=i-1;j>=0&&arr[j]>arr[j+1];j--){int temp=arr[j];arr[j]=arr[j+1];arr[j+1]=temp;}}}
四、归并排序
原理:一个数组排序,先给左边排好序,再给右边排好序,最后让整体有序。
排序运用了递归的方法,在整体有序的过程中运用了双指针。
时间复杂度为O(N*logN)
空间复杂度O(N)
左边排好序的数组与右边排好序的数组中的元素从各自的第一个元素开始两两比较,满足条件就向下边的辅助数组中放元素,指针向右移,继续比较,最后哪个数组有剩余的元素挨个放到辅助数组当中去。最后数组做到有序。
public static void mergeSort(int[] arr){if(arr==null||arr.length<2){ //无效数组直接返回return;}mergeSort(arr,0,arr.length-1);}private static void mergeSort(int[] arr, int l, int r) {if (l==r){return;}int mid=l+((r-l)>>1); mergeSort(arr,l,mid); //递归mergeSort(arr,mid+1,r); //递归merge(arr,l,mid,r);}private static void merge(int[] arr, int l, int mid, int r) {int p1=l;int p2=mid+1;int i=0;int[] help=new int[r-l+1];while (p1<=mid&&p2<=r){ //数组比较 下放过程help[i++]=arr[p1]<=arr[p2]?arr[p1++]:arr[p2++];}//哪个数组有剩余就依次放入辅助数组中while (p1<=mid){ help[i++]=arr[p1++];}while (p2<=r){help[i++]=arr[p2++];}for (i=0;i<help.length;i++){arr[l+i]=help[i];}}
五、快速排序
原理:荷兰国旗思想,把数组分为了三个区域,小于这个数的放左边区域,等于这个数放中间区域,大于这个数的放右边区域,递归从而让数组整体有序。
时间复杂度O(N*logN)
空间复杂度O(logN)
在快速排序中,往往需要从数组中找个随机数来作为划分值。和归并排序一样都是使用了压栈(先入
后出)的思想。
public static void quickSort(int[] arr){if (arr==null||arr.length<2){return;}quickSort(arr,0,arr.length-1);}private static void quickSort(int[] arr, int l, int r) {if (l<r){swap(arr,(int)(l+(Math.random()*(r-l+1))),r); //从数组中随机选取一个作为划分值int[] p=partition(arr,l,r); //返回左边界和右边界quickSort(arr,l,p[0]-1);//递归quickSort(arr,p[1]+1,r);//递归}}private static int[] partition(int[] arr, int l, int r) {int less=l-1;int more=r;while (l<more){if (arr[l]<arr[r]){swap(arr,++less,l++);}else if(arr[l]>arr[r]){swap(arr,l,--more);}else {l++;}}swap(arr,more,r);return new int[]{less+1,more};}
六、堆排序
堆结构分为大根堆(最大堆)和小根堆(最小堆),堆顶为这个堆的最大或最小值,在一个大根堆中,任何一个父节点的值,都大于或等于它左,右孩子节点的值。小根堆同理。利用堆的结构,可以进行排序。
原理:在把数组调整为堆结构之后,把堆顶与最后一个元素进行交换,然后把现在的最后一个元素“抛出”,然后在调整堆结构,调整完毕的堆顶元素就成为了原数组中的第二大的元素,然后重复刚才的操作,直到堆中的元素全部“抛出”。排序完成。
时间复杂度O(N*logN)
空间复杂度O(1)
public static void heapSort(int[] arr){if (arr==null||arr.length<2){return;}for (int i=0;i<arr.length;i++){heapInsert(arr,i); //把数组调整为大根堆}int heapSize=arr.length;swap(arr,0,--heapSize); //交换最大值while (heapSize>0){heapify(arr,0,heapSize); //下沉操作 调整堆结构swap(arr,0,--heapSize);}}private static void heapInsert(int[] arr, int index) {while (arr[index]>arr[(index-1)/2]){swap(arr,index,(index-1)/2);index=(index-1)/2;}}private static void heapify(int[] arr, int index, int heapSize) {int left=2*index+1;while (left<heapSize){int largest=left+1<heapSize&&arr[left+1]>arr[left]?left+1:left;largest=arr[largest]>arr[index]?largest:index;if (largest==index){break;}swap(arr,index,largest);index=largest;left=2*index+1;}}
桶排序
1、计数排序
2、基数排序
这两种排序都是基于桶排序思想下的排序,都是不基于比较的排序。
七、计数排序
取一个合适长度的计数数组,把需要排序的数组中的元素依次统计在计数数组当中去(统计当前数有多少个),最后按照顺序输出。
时间复杂度O(N)
空间复杂度O(N)
private static void countSort(int[] arr) {if(arr==null||arr.length<2){return;}int max=Integer.MIN_VALUE;int min=Integer.MAX_VALUE;for (int i=0;i<arr.length;i++){min=Math.min(min,arr[i]);max=Math.max(max,arr[i]);}int[] count=new int[max-min+1]; //给计数数组合适长度for (int i=0;i<arr.length;i++){count[arr[i]-min]++; //统计}int i=0;for (int j=0;j<count.length;j++){while (count[j]-->0){arr[i++]=j+min; //根据下标完成排序}}}
八 、基数排序
基数排序是根据数组中最大数的位数来模拟的几次入桶出桶,同时也有个长度为10的计数器,来给每一次入桶计数,完成了几次的入桶出桶,数组整体就会有序。
时间复杂度O(N)
空间复杂度O(N)
- 首先在数组中找到最大值,来确定入桶出桶的次数。
- 创建一个长度为10的计数数组,创建一个辅助数组。
- 为数组中元素某位的数进行计数到计数数组当中去,并且变成前缀和。
- 从数组最右边的元素开始入桶,例如上图中,062为最右边的数,个位数是2,定位到count的数组下标为2的元素,元素减去1的值为3,为元素在辅助数组中的下标,然后倒数第二的元素,052,个位数为2,定位到count的数组下标为2的元素,元素减去1的值就变成2,为元素在辅助数组中的下标,就这样遍历一轮,完成一次入桶。
- 完成已经确定的入桶出桶的次数后,最后就排好了序。
private static void radixSort(int[] arr, int begin, int end, int digit) {final int radix=10;int i=0,j=0;int[] bucket=new int[end-begin+1];for (int d=1;d<=digit;d++){ //有多少位就进出几次int[] count=new int[radix];for(i=begin;i<=end;i++){//count[0] 当前位(d位)是0的数字有多少个//count[1] 当前位(d位)是0,1的数字有多少个//count[2] 当前位(d位)是0,1,2的数字有多少个//count[i] 当前位(d位)是(0-i)的数字有多少个j=getDigit(arr[i],d);count[j]++;}for (i=1;i<radix;i++){ //前缀和count[i]=count[i]+count[i-1];}for (i=end;i>=begin;i--){ //入桶j=getDigit(arr[i],d);bucket[count[j]-1]=arr[i];count[j]--;}for (i=begin,j=0;i<=end;i++,j++){ //出桶arr[i]=bucket[j];}}}private static int getDigit(int i, int d) { //得到某位的数return (i/((int) Math.pow(10, d-1))%10);}
总结
前六个排序都是基于比较的排序,后两个排序都是不基于比较的排序,需要有比较合适的数据状况才能使用,所以说这些不基于比较的排序使用范围还是很有限的。
基于比较的排序也都各有优缺,得看需求来选择。
时间复杂度 | 空间复杂度 | 排序稳定性 | |
---|---|---|---|
选择排序 | O(N^2) | O(1) | 不具备 |
冒泡排序 | O(N^2) | O(1) | 具备 |
插入排序 | O(N^2) | O(1) | 具备 |
归并排序 | O(N*logN) | O(N) | 具备 |
快排(一般排序选择) | O(N*logN) | O(logN) | 不具备 |
堆排 | O(N*logN) | O(1) | 不具备 |
计数排序 | O(N) | O(N) | 具备 |
基数排序 | O(N) | O(N) | 具备 |
程序员必备的八大排序算法相关推荐
- 程序员必备十大排序算法
程序员必备十大排序算法 常见排序算法 基本概念 插入排序 直接插入排序 排序思路 排序过程 代码实现 算法分析 折半插入排序 排序思路 排序过程 代码实现 算法分析 希尔排序 排序思路 排序过程 代码 ...
- 蜡炬教育推荐:程序员必备的5本算法书籍
原标题:蜡炬教育推荐:程序员必备的5本算法书籍 由于近几年大数据.机器学习.人工智能方向的持续火爆,算法越来越被程序员重视,实际上算法比编程语言本身更加重要. 今天,蜡炬教育老师就为大家推荐几本经典的 ...
- 成为优秀程序员必备的八大学习网站
一.CSND(国内最大中文IT社区) 国内的程序员入门级网站,内容很多很杂,包括论坛.资源下载.博客.各种资讯等等. 二.博客园 个人觉得国内比较好的技术博客网站,很多偏Windows开发的大牛在这里 ...
- 程序员的艺术:排序算法舞蹈
1.冒泡排序: 2.希尔排序: 3.选择排序: 4:插入排序: 5.快速排序: 6.归并排序: 转载于:https://www.cnblogs.com/jxgxy/archive/2012/08/20 ...
- c语言的八大排序算法,程序员的内功:C语言八大排序算法
四 一.冒泡排序 冒泡排序算法的运作如下: ●比较相邻的元素.如果第一个比第二个大,就交换他们两个. ●对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.这步做完后,最后的元素会是最大的数. ...
- 程序员必备算法,排列组合
还记得排列组合吗? 在高中的时候最常接触的莫过于排列组合了,毕竟高考必考的嘛.我们先来回忆下这两个的公式是啥: 排列组合公式 如果看到这个还有一丢丢的印象,说明大家的基础都还不错.那么问题来了,大家都 ...
- 视频教程-程序员必备算法课!(揭秘淘宝购物车算法)-机器学习
程序员必备算法课!(揭秘淘宝购物车算法) CSDN讲师名下集合了诸多业界知名讲师的公开课内容,内容涵盖人工智能.大数据.区块链等诸多热门技术领域的最佳技术实践,聚合美团.滴滴.AWS.科大讯飞等知名企 ...
- C语言八大排序算法,附动图和详细代码解释!
文章来源:电子工程专辑.C语言与程序设计.竹雨听闲 一.前言 如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功. 想写出精炼.优秀的代码,不通过不断的锤炼,是很难做到的. 二. ...
- 硬核!C语言八大排序算法,附动图和详细代码解释!
来源 :C语言与程序设计.竹雨听闲等 一 前言 如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功. 想写出精炼.优秀的代码,不通过不断的锤炼,是很难做到的. 二 八大排序算法 ...
- 序列划分c语言,一篇“get”C语言八大排序算法
如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功. 想写出精炼.优秀的代码,不通过不断的锤炼,是很难做到的. 二.八大排序算法 排序算法作为数据结构的重要部分,系统地学习一下是 ...
最新文章
- iOS 11开发教程(二)编写第一个iOS 11应用
- python列表可以加可以乘
- Sybase资料下载(参考手册,功能讲解很全)
- 保障了罗振宇跨年演讲的PTS铂金版正式上线,产品体验全新升级
- 移动端页面制作字号大小设定问题,设计稿文字字号规范,解决移动端大小屏适配问题
- Oracle SUn
- BMP文件格式详解(BMP file format) (转)
- 第五章 线性回归 学习笔记下
- HTML5 Form Data 对象的使用
- 最新的windows xp sp3序列号 xp序列号
- 5600高流明更清晰 NEC CF6600U投影试用
- TIA博途软件中程序编辑区标题上的收藏快捷指令取消了,如何恢复显示?
- unity碰撞检测识别对象的几种方法,刚体篇
- 建筑识图与构造【1】
- codeforces 718E. Matvey's Birthday
- php连接不同编码oracle,PHP连接Oracle出现中文乱码问题
- SSD为什么需要Trim?
- 3DMAX 导出ogre模型,骨骼(.mesh/.skeleton)
- 基于html5贪吃蛇小游戏,使用HTML5 Canvas制作贪吃蛇小游戏
- 服务器内存条位置插错,电脑内存条应该怎么插?插错位置,你的电脑甚至开不了机...
热门文章
- html5页面关闭的回调函数,js回调函数例子 js 回调函数问题的执行结果想作为返回值...
- python分行政区域汇总_python:编写行政区域三级菜单(day 1)
- Java开源 J2EE框架(一)
- yalmip简单的例子
- python--查询PG数据库
- tomcat修改端口号 / 同时运行多个tomcat
- 黑域,黑阈 Permission denied
- canny算法(3)——非极大值抑制
- matlab:Matlab基础教程 第三章 数组和向量
- Docker入门教程