zoukankan      html  css  js  c++  java
  • 时间复杂度

    时间复杂度

    先来一段有趣的对话

    1
    2
    3
    4
    5

    看到时间复杂度的重要性了吧

    那什么是时间复杂度呢

    7

    一天过后,小灰和大黄各自交付了代码,两端代码实现的功能都差不多。大黄的代码运行一次要花100毫秒,内存占用5MB。小灰的代码运行一次要花100秒,内存占用500MB。于是......

    8
    9

    由此可见,衡量代码的好坏,包括两个非常重要的指标:

    • 运行时间;
    • 占用空间。

    10

    我们先看一下标准的定义

    定义:如果一个问题的规模是n,解这一问题的某一算法所需要的时间为T(n),它是n的某一函数 T(n)称为这一算法的“时间复杂性”。

    当输入量n逐渐加大时,时间复杂性的极限情形称为算法的“渐近时间复杂性”。

    我们常用大O表示法表示时间复杂性,注意它是某一个算法的时间复杂性。大O表示只是说有上界,由定义如果f(n)=O(n),那显然成立f(n)=O(n^2),它给你一个上界,但并不是上确界,但人们在表示的时候一般都习惯表示前者。

    此外,一个问题本身也有它的复杂性,如果某个算法的复杂性到达了这个问题复杂性的下界,那就称这样的算法是最佳算法。

    • “大O记法”:在这种描述中使用的基本参数是n,即问题实例的规模,把复杂性或运行时间表达为n的函数。这里的“O”表示量级 (order),比如说“二分检索是 O(logn)的”,也就是说它需要“通过logn量级的步骤去检索一个规模为n的数组”记法 O ( f(n) )表示当 n增大时,运行时间至多将以正比于 f(n)的速度增长。

    • 常见的时间复杂度

      • 按数量级递增排列,常见的时间复杂度有:

    [常数阶O(1)<对数阶O(logn)<线性阶O(n)<线性对数阶O(nlogn)<平方阶O(n^2)<立方阶O(n^3)<...<k次方阶O(n^k)<指数阶O(2^n)$$($log2n= logn$) 其中, $$O(n),O(n^2), 立方阶O(n^3),..., k次方阶O(n^k)$$ 为多项式阶时间复杂度,分别称为一阶时间复杂度,二阶时间复杂度。。。 $$O(2^n)$$指数阶时间复杂度,该种不常见 $$对数阶O(logn),线性对数阶O(nlogn)$$ 除了常数阶以外,该种效率最高 ##如何计算时间复杂度 * 通常情况下,我们看循环次数来计算时间复杂度 * 举个栗子 $$sum_{i=1}^nfrac{1}{2}(n-i+1)(n-i+2)]

    那这里,它的时间复杂度就是(O(n^3))
    原式(Rightarrow sum_{i'=1}^nfrac{1}{2}i(i+1))
    (Rightarrow frac{1}{2}sum_{i'=1}^ni^2+frac{1}{2}sum_{i'=1}^ni)前一个(O(n^3))后一个(O(n^2))
    * 如果这个比较抽象,那随便来段代码

    for(i=0;i<n;i++)
        {  
           for(j=0;j<i;j++)  
           {
              for(k=0;k<j;k++)
                 x=x+2;  
           }
        }
    

    那我们可以看到,代码中出现了三层循环,那么我们可以认为它的时间复杂度为(O(n^3))

    当i=m,j=k的时候,内层循环的次数为k

    当i=m时,j可以取 (0,1,…,m−1)

    所以这里最内循环共进行了(0+1+…+m−1=frac{(m−1)m}{2})

    所以,i从0取到n, 则循环共进行了:(0+frac{(1−1)×1}{2}+…+frac{(n−1)n}{2}=frac{n(n+1)(n−1)}{6})

    所以时间复杂度为(O(n^3))

    • 平时听到某些大佬口中的(O(1))是什么呢?
      temp=i;i=j;j=temp; 遇到这样的语句,我们可能会听到“使用(O(1))查询。。。”之类的话语。实际上与n无关,只是在执行语句。

    • 当然,在一些场合,你可能会听到频度这个词。那频度又是什么?(很明显我前面忘说了)

      • 还是来看一下标准定义

    一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为(T(n))

    * 其实我也没太看懂
    * 所以还是举个栗子吧
    假设$T(n)=2n^2+n+1$,那么我们就可以忽略n的最高次项的系数,以及其他项(包括常数项),认为$T(n)=O(n^2)$
    当然,你也可以类比一下。
    物理老师上课讲过当$m<<M$的时候,表达式$a=frac{M}{M+m}g$忽略m的取值,即m微小到不对结果起到作用/手动@yyp/
    * 样例代码呢。。。
    
    for (i=1;i<n;i++) {
        y=y+1;         ①   
        for(j=0;j<=(2*n);j++)   { 
        x++; }       ②      
    }
    

    像这样,代码中语句①的频度是(n−1)

    语句②的频度是((n−1)∗(2n+1)=2n^2−n−1)

    (f(n)=2n^2−n−1+(n−1)=2n^2−2)(f(n)上面提到了)

    该程序的时间复杂度(T(n)=O(n^2))

    i=1;       ①
    while (i<=n)
        i=i*2; ②
    

    语句①的频度是1

    到这里,又卡住了,语句②是什么鬼。。。(我也不知道)

    那我们可以设语句②的频度是(f(n)), 则:(2^{f(n)}≤n)(f(n)≤logn)

    取最大值(f(n)=logn)(T(n)=O(logn))

    • 总结一下(来源于网络

    一般情况下,算法的基本操作重复执行的次数是模块n的某一个函数(f(n)),因此,算法的时间复杂度记做:(T(n)=O(f(n)))。随着模块n的增大,算法执行的时间的增长率和(f(n))的增长率成正比,所以(f(n))越小,算法的时间复杂度越低,算法的效率越高。

    在计算时间复杂度的时候,先找出算法的基本操作,然后根据相应的各语句确定它的执行次数,再找出(T(n))的同数量级(它的同数量级有以下:(logn, n, nlogn, n^2, n^3, 2^n,n!)),找出后,(f(n)=该数量级),若(frac{T(n)}{f(n)})求极限可得到一常数c,则时间复杂度(T(n)=O(f(n)))

    • 看到上面那个求极限了?就是

    [lim_{n ightarrow+infty}frac{T(n)}{f(n)} ]

  • 相关阅读:
    STM32:SPI&w25qxx的配置与代码
    STM32:USART的原理与配置
    C的抽象数据类型:二叉树
    DSP:TMS320C66x 系列SPI NOR自启动
    C的抽象数据类型:链表、队列
    STM32:GPIO口的使用
    STM32:时钟树
    STM32:预备知识
    makefile:简单小结
    ubuntu:tar、apt、vim、gcc的配置和简单使用
  • 原文地址:https://www.cnblogs.com/orange-233/p/12037475.html
Copyright © 2011-2022 走看看