一、算法效率
算法效率分为时间效率和空间效率。
时间效率
时间复杂度,衡量一个算法的运行速度。
空间效率
空间复杂度,衡量一个算法所需要的额外空间。
二、时间复杂度
概念
算法的时间复杂度是一个数学函数,描述了该算法的运行时间。一个算
法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。
大O的渐进表示法
1、演示
void f1(int n){ int count =0; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) {//N^2 count++; } } for (int k = 0; k < 2*n; k++) {//2N count++; } int m=10; while((m--)>0){//10 count++; } System.out.println(count); }
f1执行的基本操作次数:F(N)=N^2+2N+10
实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法。
2、推导大O阶方法
1、用常数1取代运行时间中的所有加法常数。
F(N)=N^2+2N
2、在修改后的运行次数函数中,只保留最高阶项。
F(N)=N^2
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
F(N)=N^2
使用大O的渐进表示法后可得到f1的时间复杂度为:O(N^2)
大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次
最好情况:任意输入规模的最小运行次数(下界)
在实际中一般情况关注的是算法的最坏运行情况。
3、常见的时间复杂度
O(1) < O(log2N) < O(N) < O(Nlog2N) < O(N^2)
void f2(int n){ int count=0; for (int i = 0; i < 100; i++) {//O(1) count++; } System.out.println(count); }
int binarySearch(int[] array,int value){//二分查找 int begin=0; int end=array.length-1; while(begin<=end){//O(log2N) int mid=begin+((end-begin)/2); if(array[mid]<value) begin=mid+1; else if(array[mid]>value) end=mid-1; else return mid; } return -1; }
结合二分查找思想
数据个数 | 次数 |
2 | 2 |
4 | 3 |
8 | 4 |
N | X |
执行次数:X=log2N+1
时间复杂度:O(log2N)
long factorial(int n){ //递归 递归的次数*每次递归后代码的执行次数 //N*1 //O(N) return n<2?n:factorial(n-1)*n; }
三、空间复杂度
概念
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度算的是变量的个数。空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。
实例
void bubbleSort(int[] array){ for(int end=array.length;end>0;end--){ boolean sorted=true;//问题的规模:n个数据 //sorted 空间复杂度 O(1) for(int i=1;i<end;i++){ if(array[i-1]>array[i]){ Swap(array,i-1,i); sorted=false; } } if(sorted==true){ break; } } }
long[] fibonacci(int n){ long[] fibArray=new long[n+1]; fibArray[0]=0; fibArray[1]=1; for(int i=2;i<=n;i++){ fibArray[i]=fibArray[i-1]+fibArray[i-2];//O(N) } return fibArray; }
long factorial(int N){ return N<2?N:factorial(N-1)*N;//O(N) }