8.时间频度和时间复杂度

度量一个程序算法执行时间的两种方法
  • 事后统计法: 直白就是把程序跑一边,统计程序从开始到结束花费的时间。缺点在于需要将程序跑一边,如果越到耗时程序的时候效率不高,而且要求计算机的硬件软件的环境一致,保证运行环境相同才有可信度。
  • 事后统计法: 通过分析某一个程序算法具体的时间复杂度来度量一个算法的优劣。
时间频度

一个算法花费的时间与算法中语句执行数成正比。哪个算法执行的次数越多,则它花费的时间就多。一个算法中语句执行的次数成为时间频度,记做T(n)。

例如:计算1-100的总和

// 方式1
int total = 0;
int num = 100;
for(int i=0;i<=num;i++){
    total = i+total;
}

// 方式2
int num = 100;
int total = (1+num)*num/2

此时方式1中的时间频度为100+1次 记为 T(n)=n+1 n=100因为循环了100次 +1是因为有一个判断

方式2的时间频度为1 因为只有一条语句 记为 T(n)=1

时间复杂度

时间复杂度是度量算法花费时间,算法中的基本操作语句和重复执行次数是问题规模N的某个函数,用T(n)表示,若有有个辅助函数f(n),当n趋近无穷大时,T(n)/f(n)的极限值为一个不等于零的常数,则称f(n)和T(n)是同数量级的函数记为 T(n)=O(f(n)),简称O(n),为一个算法的渐进时间复杂度,简称时间复杂度。

时间复杂的计算方法
  1. 分析出算法的运行时间频度
  2. 用常数1代替算法中所有加法常数 如 T(n)=2n²+5n+5 ==> T(n)=2²+5n+1
  3. 只保留最高阶项 如 T(n)=2n²+5n+5 ==> T(n)=2n²
  4. 取出最高阶的系数 T(n)=2n²+5n+5 ==> T(n)=n² 则最终时间复杂度为 T(n)=n²记为O(n²)
常见时间复杂度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OhRClVG-1594869812967)(C:\Users\denglw\AppData\Roaming\Typora\typora-user-images\image-20200715103543819.png)]

  1. 常数阶 O(1)

    无论代码执行了多少行,只要没有循环等复杂结构时间复杂度为O(1)

    int i = 1;
    int j = 2;
    i++;
    j++;
    int total = i+j;
    

    ​ 上述代码时间消耗不会随着变量的增长而增长,即i=1或者i=10000都是一样的,无论有多少行,一行或者及万行都可以用O(1)来表示时间复杂度。

  2. 对数阶 O(log2n)

    int i = 1;
    int n = 1024;
    while(i < n){
        i = i*2;
    }
    // 或者
    for(int i=0; i<n; i*=2){
        System.out.println(i);
    }
    

    上述代码中while循环或者for 循环 的执行次数为 以2为底数1024的对数 log2N,当N增大时,时间频度成对数上升,类似于一根长16M的绳子,每次割一半,割到一米需要几次的问题,第一次为8M,第二次为4M,第三次为2M,第四次为1M,则时间频度具体值为4,为log16。则可以记做O(logn)。上述如果把i=i2改成 i=i3 则变成了 log3N 以3为底N的对数了.

  3. 线性阶 O(n)

    int n =100;
    for(int i=0; i<n; i++){
        System.out.println(i);
    }
    

    则表示for循环中需要执行多少次,上述代码是一个线性的,随着N的增加,执行次数就增加N次。如n=100 则执行100次 n=200则执行200次,在坐标轴上是一条直线上升的趋势。记为O(n)

  4. 线性对数阶 O(nlog2n)

    int n =100;
    int m = 1024;
    for(int i=0; i<n; i++){
           while(i < m){
            i = i*2;
        }
    }
    

    简单的理解就是一个对数阶的代码循环N遍则变成了线性对数阶,上述代码中 while循环是一个对数阶 为log1024 记做logN for循环是一个线性阶 n n=100 则他们一起的时间复杂度为O(nlogN)

  5. 平方阶 O(n^2)

    int n = 100;
    int m = 100;
    for (i=0; i < n ; i++){
        for(i=0; i < m ;i++){
            System.out.println(i);
        }
    }
    

    平方阶就是循环套循环,2层循环就是一个n2的平方阶,时间复杂度就是O(n2)

  6. 立方阶 O(n^3)

    立方阶则是3层循环嵌套

  7. k 次方阶 O(n^k)

    k层循环嵌套

  8. 指数阶 O(2^n)

    long function1(int n) {    
        if (n <= 1) {        
            return 1;
        } else {        
            return function1(n - 1) + function1(n - 2);
        }
    }
    

    类似上述从出现递归的时候,T(0) = T(1) = 1,同时 T(n) = T(n - 1) + T(n - 2) + 1,这里的 1 是其中的加法算一次执行。显然 T(n) = T(n - 1) + T(n - 2) 是一个斐波那契数列,通过归纳证明法可以证明,当 n >= 1 时 T(n) < (5/3)^n,同时当 n > 4 时 T(n) >= (3/2)^n。所以该方法的时间复杂度可以表示为 O((5/3)^n),简化后为 O(2^n)。

上述时间复杂度从上到下一次递增,在程序设计过程中需要避免指数阶的时间复杂度。

空间复杂度

指程序算法运行过程中对临时占用存储空间如内存的大小,不过从用户体验来是说,用户并不关系后台占用的具体多少内存,只关心多久能给我反馈即执行的速度,所以出现了很多缓存产品,本质上就是用空间换时间的过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值