• 空间复杂度&时间复杂度


    @

    老说时间复杂度,空间复杂度,能不能简单描述一下?说人话!

    空间复杂度

    概念

    Space Complexity,对一个算法在运行过程中临时占用存储度空间的度量,记做S(n)=O(f(n));

    其实白话就是,一段程序运行需要分配的空间,我们用一个线性函数来描述它的变化趋势,我们把这个变化趋势整体就叫做这个算法的空间复杂度!

    示例

    来看以下代码示例:

    int a = 1;
    a++;
    int b = 2;
    b+=1;
    int c = a + b;
    
    int n = 10;
    int [] arr = new int[n];
    
    int mi = 2;
    int m = (int)Math.pow(n,mi);
    int [] arr1 = new int[m];
    

    那么上面一段代码的空间复杂度分别怎么表示呢?

    可以看到因为a,b,c 三个变量都是加减操作,存储空间根据字节长度有关,它们的字节都是线性增长的,所以它的空间复杂度我们记做:
    $$
    S(n)=O(1)
    $$
    arr 数组分配的空间和它的初始长度n 相关,所以它的空间复杂度我们记做:
    $$
    S(n) = O(n);
    $$
    arr1 数组分配的空间和它的初始长度m 相关,而m 是n的mi次方即: m = n^mi

    这里是mi为2, 则arr1的空间复杂度我们记做:
    $$
    S(n) = O(n^2)
    $$

    时间复杂度

    概念

    Time Complexity, 对一个算法运行时所需要消耗的时间的度量,记做:T(n) = O(f(n));

    白话理解就是一个程序运行所需要的时间,我们并不是直接描述它占用时间的长短,而是从宏观上评估它的所消耗时间的一个趋势,而它的变化趋势我们也可以用各种线性函数来表示(即所写代码的执行次数和什么相关的函数),那这种线性函数的描述方式我们叫做时间复杂度;

    来看以下代码示例:

    O(1)

    int count;
    int i = 1;
    int j = 2;
    int k = 3;
    count = i + j + k;
    

    从上面代码我们可以看到,这段代码程序是自上向下执行一次的,那么对于这种只执行一次的代码时间复杂度我们记做:
    $$
    T(n)=O(1)
    $$

    O(log3n)

    int n = 100;
    int i = 1;
    while(i<=n){
        i=3*i;
    }
    

    在上面代码中,while循环每次i都自增3倍,如果自增x次后i>n就退出循环了,也就是3的x次方时退出了循环,可以确定的是x次循环后i一定是一个大于n的某个值,在时间复杂度的考量中我们将此值忽略直接记做n,那么3的x次方等于n,成对数即是x = log(3)(n)。说明这段代码的执行次数x 是个对数函数,对应的时间复杂度我们记做:
    $$
    T(n) = O(log_3n)
    $$

    O(n)

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

    上面代码是一个简单的for循环,那么很明显它的执行次数和n的大小有关,我们将这种for循环的时间复杂度记做:
    $$
    T(n)=O(n)
    $$

    O(nlogN)

    int n = 1000;
    int j;
    for(int i = 0;i<n;i++){
        j = 1;
        while(j<n){
            j = 2*j;
        }
    }
    

    在上面一段代码中,我们可以看到for循环中每次都对i 重新做了赋值操作;

    保证 while 循环每次都能执行log(2)(n)次,那么它总的执行次数就是n*log(2)(n), 那么这个时候决定执行的次数的关键就在于n的大小了,至于是2倍还是几倍的增长变得不再那么重要,我们可以忽略(极限思维)统一记做N。那么它的时间复杂度我们就记做:
    $$
    T(n)= O(nlogN)
    $$

    O(n^k)

    int n = 100;
    for(int i = 0;i<n;i++){
    
        for(int j = 0;j<n;j++){
    
            for(int k = 0;k<n;k++){
    
            }
        }
    }
    

    上面代码三个for循环,明显执行了n* n * n即n^3,它的时间复杂度我们记做:
    $$
    T(n) = O(n^3)
    $$

    O(2^n),O(n!)

    实际上幂指数增长和穷举,基本没有见过这样的程序,你想什么样的算法会是指数性的和穷举型的?(网络攻击?这两个不常见,了解即可)

    常见时间复杂度函数图

    从图中我们可以看到趋势越陡的函数时间复杂度肯定大,那么以上的时间复杂度从大到小依次是:
    2^n > (n^3)/3 > 5n^2 > 500log(2)(n) > 100n

    那么我们可以推断出常见的时间时间复杂度从大到小依次是:
    $$
    O(2^n) > O(n3)>O(n2)>O(nlog_2n)>O(n)>O(log_2n)>O(1)
    $$

    时间复杂度越大,算法的执行效率越低!

    参考文章

    最后关于时间复杂度的更形象的总结,推荐博客 :一套图 搞懂“时间复杂度”

    关于8大排序算法时间复杂度稳定性的总结,推荐博客:八大排序算法、稳定性及时间复杂度

    小结:我们学习了解任何知识,一定不能死啃概念,要试着把自己不能理解的东西抽象成自己可以理解的东西! 很多东西我们不能理解,是很多时候是有些技术类文章不说人话。有些也是自己眼界见识不够,而有些则是说的人能力不够还无法做到通俗易懂的讲解出来!如果你能做到通俗易懂的讲解出来,那说明你已经掌握了!

    余路那么长,还是得带着虔诚上路...
  • 相关阅读:
    .Net需要掌握的知识
    图片轮播
    vector
    2016ACM青岛区域赛题解
    总是有一个程序的bug没找到
    poj1001_Exponentiation_java高精度
    poj2236_并查集_Wireless Network
    poj1703_Find them, Catch them_并查集
    poj2492_A Bug's Life_并查集
    poj1182食物链_并查集_挑战程序设计竞赛例题
  • 原文地址:https://www.cnblogs.com/itiaotiao/p/12848627.html
Copyright © 2020-2023  润新知