11

解惑3:时间频度,算法时间复杂度

 4 years ago
source link: http://www.cnblogs.com/Createsequence/p/13198170.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一、概述

先放百科上的说法:

算法的 时间复杂度 (Time complexity)是一个函数,它定性描述该算法的运行时间。这是一个代表算法输入值的字符串的长度的函数。

时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。

例如,如果一个算法对于任何大小为 n (必须比 n0 大)的输入,它至多需要 5 n 3 + 3 n 的时间运行完毕,那么它的渐近时间复杂度是 O( n 3).

二、时间频度

要理解时间复杂度,需要先理解时间频度,而时间频度简单的说,就是 算法中语句的执行次数

举个例子:

要计算1+2+...+100,现在有两种算法

public int fun1(int n){
    int total;
    for(int i = 0; i <= n; i++){
        total+=i;
    }
    return total;
}

public int fun2(int n){
    int total = (1 + n)*n/2;
    return total;
}

我们可以看见,对于 fun1() 这个方法,不管n多大,永远需要执行n+1次,也就是说他的时间频度是T(n)=n+1,

而对与 fun2() 来说,不管n多大都只需要执行1次,所以他的时间频度T(n)=1。

当n趋向无穷大时,有三个忽略:

1.忽略常数项

比如T(n)=2n+1,当n趋向无穷大时,可以忽略常数项1;

参见下图:

  • 2n+20 和 2n 随着n 变大,执行曲线无限接近, 20可以忽略
  • 3n+10 和 3n 随着n 变大,执行曲线无限接近, 10可以忽略

Jjq2emB.png!web

2.忽略低次项

比如T(n)=2n+3n^8,当n趋向无穷大时,可以忽略低次项及其系数2n;

参见下图:

  • 2n^2+3n+10 和 2n^2 随着n 变大, 执行曲线无限接近, 可以忽略 3n+10
  • n^2+5n+20 和 n^2 随着n 变大,执行曲线无限接近, 可以忽略 5n+20

iaie2eF.png!web

3.忽略系数

比如T(n)=2n^8,当n趋向无穷大时,可以忽略系数2。

参见下图:

  • 随着n值变大,5n^2+7n 和 3n^2 + 2n ,执行曲线重合, 说明 这种情况下, 5和3可以忽略。
  • 而n^3+5n 和 6n^3+4n ,执行曲线分离,说明多少次方式关键

JviYNbJ.png!web

三、时间复杂度

我们现在理解了时间频度的T(n)的含义,假设当有一个辅助函数f(n),使得 当n趋近无穷大时 ,T(n)/f(n)的极限值为不等于0的常数,就叫f(n)为T(n)的同量级函数,记作T(n)=O(f(n)),

称O(f(n))为算法的 时间渐进复杂度 ,也就是 时间复杂度

又根据时间频度T(n)的“三个忽略”原则,我们可以知道时间复杂度是这样得到的:

  1. 忽略所有常数
  2. 只保留函数中的最高阶项
  3. 去掉最高阶项的系数

举个例子:

某算法T(n)=2n^3+4n-5,按步骤走:

  1. T(n)=2n^3+4n
  2. T(n)=2n^3
  3. T(n)=n^3

即可得该算法时间复杂度为O(n^3)

四、常见时间复杂度

这里按复杂度从低到高列举常见的时间复杂度:

  1. 常数阶O(1)

    // 无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1) 。
    public void fun(int n){
        n+=1;
    }
  2. 对数阶O(log2n)

    // 根据公式有 n = 2^x,也就是 x = log2n,x即为循环代码执行次数,所以时间复杂度为O(log2n)
    public void fun(int n){
        int i = 1;
        while(i < n){
            i = i *2
        }
    }
  3. 线性阶O(n)

    // 一般来说,只要代码里只有一个循环结构,即输入规模和执行次数呈线性相关,那这个代码的时间复杂度就都是O(n) 。
    public void fun(int n){
        for(int i = 0; i < n; i++){
            n+=i;
        }
    }
  4. 线性对数阶O(nlogn)

    // 可以简单理解为对数阶的程序被放入了循环结构中,也就是n*O(logn),下面的代码的复杂度就是O(nlog2n)
    public void fun(int n){
        int j = 1;
        for(int i = 0; i < n; i++){
            while(i < n){
                j = j *2
            }
        }
    }
  5. 平方阶O(n²),立方阶O(n

    3),K次方阶O(n

    k)
    // 平方阶可以简单理解为线性阶中嵌套一个线性阶,也就是O(logn)*O(logn),下面的代码复杂度就是O(n^2)
    // 立方阶同理,就是三个线性阶的嵌套,K次方阶同理
    public void fun(int n){
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; i++){
    			i=i+j;
            } 
        }
    }

五、复杂度的四个概念

  1. 最坏情况时间复杂度:代码在最理想情况下执行的时间复杂度。
  2. 最好情况时间复杂度:代码在最坏情况下执行的时间复杂度。
  3. 平均时间复杂度:用代码在所有情况下执行的次数的加权平均值表示
  4. 均摊时间复杂度:在代码执行的所有复杂度情况中绝大部分是低级别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上。基本上均摊结果就等于低级别复杂度。

举个例子:

长度为n的数组查找一个给定元素k

public void fun(int[] arr,int k){
    for(int i = 0; i < arr.length; i++){
        if(arr[i] == k){
            //找到了
        }
    }
}

上面这个方法,最好的情况下元素k就在数组第一位,复杂度为O(1),但是最坏的情况下,元素k在数组最后一位,复杂度为O(n)。

同一段代码在不同情况下时间复杂度会出现量级差异,为了更全面,更准确的描述代码的时间复杂度,我们引入这4个概念,当然,在大多数时候我们是不用特意区分这四种情况的。

六、总结

总结一下如何快速判断程序的时间复杂度:

  • 只关注循环最多的那部分代码
  • 总复杂度等于量级最大的那段代码的复杂度
  • 嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

Recommend

  • 15

    本文是覃超老师的《算法训练营》的学习笔记,此笔记的内容包含了学习后的个人记录、个人总结、理解和思想。从而更好的学习算法。 前言 学习任何一门知识的时...

  • 14
    • itimetraveler.github.io 3 years ago
    • Cache

    ”二分查找“算法的时间复杂度

    ”二分查找“算法的时间复杂度 算法的时间复杂度无非就是for、while等包含起来的基本运算单元的循环次数 1、二分查找二分查找(binary search...

  • 8

    各种排序算法时间复杂度和空间复杂度表 各种排序算法时间复杂度和空间复杂度表: 各种排序算法时间复杂度和空间复杂度表 比较时间复杂度函数的情况如下图: 比较时间复杂度函数的情况...

  • 5

    针对某一类问题的解决,我们可能需要借助算法来实现,实现的手段也可能是各式各样的。虽然最终都解决了问...

  • 4

    作为一名“程序猿”,大家应该都听过这么一句话:程序=数据结构+算法。 这句话是由瑞士计算机科学家尼古拉斯·沃斯(Niklaus Wirth)在 1984 年获得图灵奖时说的一句话,这位大佬还以这句话为名出了一本书《Algorithms + Data Structures=Programs》,从此...

  • 2
    • zhukqian.github.io 2 years ago
    • Cache

    算法的时间复杂度

    T(n) = n 1:给小灰一条长10寸的面包,小灰每3天吃掉1寸,那么吃掉整个面包需要几天 答案自然是 3 X 10 = 30天。 如果面包的长度是 N 寸呢? 此时吃掉整个面包,需要 3 X n = 3n 天。 如果用一个函数来表达这个相对...

  • 1
    • jiawea.github.io 2 years ago
    • Cache

    算法之时间复杂度

    在了解时间复杂度之前,让我们来了解一下什么是算法?算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令(我的理解是一系列解决问题的步骤),算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的...

  • 2

     目录1、算法的复杂度2、时间复杂度​3、常见时间复杂度计算举例​1、算法的复杂度算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般...

  • 3

    V2EX  ›  问与答 朋友们你们使用 Email 的频度如何?  

  • 4

    算法中的时间频度与时间复杂度一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)时间复杂度一般情况下,算法中的...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK