1.排序也称排序算法(sort Algorithm),排序是将一组数据,依指定的顺序进行排序的过程
1.1 排序的分类
(1)内部排序:指将需要处理的所有数据都加在到内部存储器中进行排序。
(2)外部排序:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序
1.2 常见的排序
(1)内部排序:插入排序(直接插入排序,希尔排序),选择排序(简单选择排序,堆排序),交换排序(冒泡排序,快速排序),归并排序,基数排序
(2)外部排序
1.3 算法的时间复杂度-衡量一个算法执行时间的两种方法
(1)事后统计的方法-先运行再看运行时间
-要想对设计的算法的运行性能进行评测,需要实际运行该程序
-所得时间的统计量依赖于计算机的硬件软件等环境因素
(2)事前估算的方法
-通过分析某个算法的时间复杂度来判断哪个算法更优
(3)时间频度
-一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度,记为T(n)。
(4)时间复杂度
-一般情况下, 算法中的基本操作语句的重复执行次数是问题规模n的某个函数,用f(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于0的常数,则成f(n)是T(n)的同数量级函数。记作T(n)=O(f(n),为算法的渐进时间复杂度,简称时间复杂度)
-T(n)不同,但时间复杂度可能相同。
-计算时间复杂度的方法:
--用常数1代替运行时间中的所有加法常数
--修改后的运行次数函数中,只保留最高阶项
--去除最高阶项的系数
-常见的时间复杂度
--常数阶O(1),对数阶O(log2n),线性阶O(n),线性对数阶O(nlog2n),平方阶O(n^2),立方阶O(n^3),k次方阶O(n^k),指数阶O(2^n)
--常见的算法时间复杂度由小到大次序如上,时间复杂度不断增大,算法的执行效率越低
-平均时间复杂度:指的是所有可能的输入实例以等概率出现的情况下,该算法的运行时间
-最坏时间复杂度:一般讨论的时间复杂度均是最坏情况下的时间复杂度,最坏情况吓得时间复杂度是算法在任何输入实例上运行时间的界限
-平均时间复杂度和最坏时间复杂度是否一样与算法有关
排序法 | 平均时间 | 最差情形 | 稳定度 | 额外空间 | 备注 |
冒泡 | O(n2) | O(n2) | 稳定 | O(1) |
n小时较好 |
交换 | O(n2) | O(n2) | 不稳定 | O(1) | n小时较好 |
选择 | O(n2) | O(n2) | 不稳定 | O(1) | n小时较好 |
插入 | O(n2) | O(n2) | 稳定 | O(1) | 大部分已排序时较好 |
基数 | O(logRB) | O(logRB) | 稳定 | O(n) | B是真数(0-9),R是基数(个十百) |
Shell | O(nlogn) | O(ns)1<s<2 | 不稳定 | O(1) | s是所选分组 |
快速 | O(nlogn) | O(n2) | 不稳定 | O(nlogn) | n大时较好 |
归并 | O(nlogn) | O(nlogn) | 稳定 | O(1) | n大时较好 |
堆 | O(nlogn) | O(nlogn) | 不稳定 | O(1) | n大时较好 |
(5)算法的空间复杂度
-算法的空间复杂度(Space Complexity)定义为算法所耗费的存储空间,是对一个算法在运行过程中临时占用存储空间大小的度量。有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元。
-算法分析主要讨论的是时间复杂度,用户体验上更加侧重程序执行的速度。一些缓存产品(Redis,memcache)和算法(基数排序)本质就是用空间换时间。
2.冒泡排序(Bubble Sorting)
2.1 思想:通过对待排序序列从前向后,依次比较相邻元素的值,若发现逆序则交换,使值较大的元素主键从前移向后部。因为排序的过程中,各元素不断接近自己的位置,若一趟比较下来没有进行过交换,说明序列有序,因此在排序过程中设置一个标志flag判断元素是否进行过交换,从而减少不必要的比较(优化可以在冒泡写完后写)。
2.2 规则
(1)一共进行数组的大小-1次的大循环
(2)每一趟排序的次数在逐渐减少
(3)如果发现在某趟排序中,没有发生一次交换,可以提前结束冒泡排序(优化)
2.3 源代码
public static void bubbleSort(int[] arr) { // TODO Auto-generated method stub //冒泡排序演变过程,时间复杂度为O(n^2) boolean flag=false;//定义标识变量,表示是否进行过交换,没有交换为false,交换为true int temp=0;//临时变量 for(int i=0;i<arr.length-1;i++) { //每一趟开始前都假设为没有交换 flag=false; for(int j=0;j<arr.length-1-i;j++) { //如果前面的数比后面的数大,则交换 if(arr[j]>arr[j+1]) { flag=true;//进行了交换 temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } System.out.printf("第%d趟排序:",i+1); System.out.println(Arrays.toString(arr)); //一趟结束后判断是否进行交换,若一趟都没有交换,则结束冒泡排序 if(!flag) { break; } } }
3.选择排序(select sorting)
3.1 属于内部排序,是从需要排序的数据中,按照指定的规则选出某一元素,再按照规定交换位置后达到排序的目的。
3.2 思想:第一次从arr[0]-arr[n-1]中选取最小值,与arr[0]交换,第二次从arr[1]-arr[n-1]中选取最小值,与arr[1]交换....第n-1次从arr[n-2]-arr[n-1]中选取最小值,与arr[n-2]交换,总共通过n-1次,得到一个按排序码从小到大排列的有序序列。
3.3 说明
(1)选择排序一共有数组大小-1轮排序
(2)每1轮排序,又是一个循环,先假定当前这个数是最小数,然后和后面的每个数进行比较,如果发现有比当前数更小的数,就重新确定最小数,并得到下标
(3)当遍历到数组的最后时,得到本轮最小数和下标
(4)交换
3.4 源代码
package cn.atguigu.sort; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; public class SelectSort { public static void main(String[] args) { // TODO Auto-generated method stub //int[] arr= {101,34,119,1}; int[] arr=new int[80000]; for(int i=0;i<80000;i++) { arr[i]=(int)(Math.random()*8000000); } Date date1=new Date(); SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String date1Str=simpleDateFormat.format(date1); System.out.println("排序前时间"+date1Str); selectSort(arr); Date date2=new Date(); String date2Str=simpleDateFormat.format(date2); System.out.println("排序后时间"+date2Str); } public static void selectSort(int[] arr) { int min=0; int minIndex=0;//最小值的下标 boolean flag=false; for(int i=0;i<arr.length;i++) { min=arr[i];//假设本身为最小值 flag=false; for(int j=i+1;j<arr.length;j++) { if(min>arr[j]) { min=arr[j];//找出a[i+1]-a[n-1]之间的最小值,记住其最小值的下标 minIndex=j; flag=true; } } if(flag) { //进行交换 arr[minIndex]=arr[i]; arr[i]=min; } } } }