路漫 2020-06-26
事前分析估算方法:
我们发现一个高级语言编写的程序在计算机上运行所消耗的时间取决于下列因素:
1.算法采用的策略和方案;
2.编译产生的代码质量;(不可控)
3.问题的输入规模(所谓的问题输入规模就是输入量的多少)
4.机器执行指令的速度;(不可控)
#include<iostream> using namespace std; /* 如果输入量为n为1 ,则需要计算1次; 如果输入量n为1亿,则需要计算1亿次; */ int main() { int sum=0; //执行1次 int n=100; //执行1次 for(int i=1;i<=n;i++){//执行了 n+1 次 sum+=i; //执行了 n+1 次 } cout<<sum<<endl; } int main() { int sum=0; //执行了1次 int n=100; //执行了1次 sum=(n+1)*n/2; //执行了1次 cout<<sum<<endl; }这两个运行时间的差距就是n和1的差距;
为了简单,我们经常忽略掉条件循环的执行次数之后,只分析内层的核心操作。
函数渐进增长:
随着规模的增大,算法的常规操作可以忽略不计;
随着规模的增大,与最高次数的数项相乘的常数可以忽略不计;
最高次的指数大的,随着n的增长,结果也会变得增长特别快。
算法函数n最高次幂越小,算法效率越高;
大o阶的表示法:
1.用常数1取代运行时间中的所有加法常数;
2.在修改后的运行次数时,只保留高阶项;
3.如果最高阶项存在,且常数因子不为1,则去除与这个项相乘的常数;
算法一: 3次
算法二: n+3次
算法三: n^2+2次
大o记法分别为:
算法一:o(1)
算法二:o(2)
算法三 :o(n^2)
常见的大O阶:
1.线性阶;
2.平方阶;
3.立方阶;
4.对数阶;
5.常数阶;
如果遇到O(n^2),O(n^3)的时候,我们就要选择优化一下代码;
public static void main(string[] args){ int n=100; for(int i=0;i<n;i++){ show(i); } } private static void show(int i){ System.out.println(i); }
该方法复杂度为O(n);
public static void main(string[] args){ int n=100; for(int i=0;i<n;i++){ show(i); } } private static void show(int i){ for(int j=0;j<i;i++){ System.out.println(i); } }
该方法复杂度为O(n^2);
public static void main(string[] args){ int n=100; show(n); //时间复杂度为 O(n); for(int i=0;i<n;i++){ show(i); } //时间复杂度O(n^2) for(int i=0;i<n;j++){ for(int j=0;j<n;j++){ System.out.println(j); } //时间复杂度为O(n^2) } } private static void show(int i){ for(int j=0;j<i;i++){ System.out.println(i); //调用其,时间复杂度为O(n); } } //所以调用其时间复杂度为 O(2n^2+n) 根据规则可化为O(n^2)
认真分析每一个的时间复杂度
特例:最坏情况
空间复杂度分析
public static int[] reversel(int[] arr){ int n=arr.length;//申请4个字节 int temp;//申请4个字节; for(int start =0,end=n-1;start<=end;start++;end--){ temp=arr[start]; arr[start]=arr[end]; arr[end]=temp; } return arr; } //时间复杂度为 O(1); public static int [] reverse2(int[] arr){ int n=arr.length;//申请4个字节 int []temp=new int[n];//申请n*4个字节+数组自身头信息开始24个字节; for(int i=n-1;i>=0;i--)// O(4n+24+4)->O(4n)->O(n) { temp[n-1-i]=arr[i]; } return temp; }
如果并未说明是 时间复杂度还是空间复杂度, 默认为 求时间复杂度;