怎么理解时间复杂度和空间复杂度

本篇内容介绍了“怎么理解时间复杂度和空间复杂度”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

创新互联建站坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都做网站、成都网站制作、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的南岔网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

我们经常可以看到这样的描述:软件=数据结构+算法,可见算法基础对于一个程序员的重要性。算法中,有两个基本概念:时间复杂度和空间复杂度。

  • 时间复杂度:描述算法执行消耗的时间,时间越短,时间复杂度越低,算法越优秀;

  • 空间复杂度:描述算法执行所占用的内存空间,占用内存越少,空间复杂度越低,算法越优秀;

因此,时间复杂度和空间复杂度是评价一个算法性能的主要指标。那么如何计算一个算法的时间复杂度和空间复杂度呢?

简单理解,计算时间复杂度就是评估一个算法完成后执行了多少行代码,也就是算法所消耗的时间,但是该如何用数学的方式其表示出来呢?

假设现在有个一个算法需要执行n次运算,我们用T(n)表示,n即表示算法的规模(比如n=10时,循环输出10次Hello World;n=100时,循环输出100次Hello World)。如果假设存在一个函数f(n),表示随着n的变化,算法需要执行的次数,当T(n)=O(f(n)),那么O(f(n))即为算法的时间复杂度。

比如,一个普通的循环:

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

当n越大,循环的次数越多,那么耗费的时间也就越大,也就是f(n)随着n线性增长。那么该算法的执行时间T(n)=O(n),即时间复杂度为O(n)。

再比如,一个双层循环:

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

外层循环每循环一次,内层循环就循环了n次,那么代码总循环次数就是n*n。那么该算法的执行时间T(n)=O(n^2) ,即时间复杂度为O(n^2)。

一般来说,时间复杂度是用来评估随着n的增大,算法执行需要消耗时间的增速,而不是精确计算消耗的时间,事实上也无法精确计算。既然是评估,那么f(n)函数我们只需要保留对消耗时间影响最大的因子即可。

例如,有一个f(n)=2*n^3函数,系数2对f(n)函数的增速影响就不大,所以该算法的时间复杂度T(n)=O(n^3),即忽略常量系数对增速的影响。

再比如,在一个没有循环的代码块里,只有三行输出代码:

public void print() {
    System.out.println("Hello 河先森");
    System.out.println("Hello 河先森");
    System.out.println("Hello 河先森");
}

即T(n)=3,是一个常数,而常数对增速的影响是可以忽略的,那么该代码块的时间复杂度就是O(1)。

再来看一个例子,计算下面代码块的时间复杂度:

public void print(int n) {
    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            System.out.println("Hello 河先森");
        }
    }
}

当i=0时,内层循环了n次,当i=1时,内层循环了n-1次,以此内推,当i=n-1时,内层循环了1次。那么总的循环次数T(n)=n+(n-1)+(n-1)+...+1=n(n+1)/2=n^n/2+n/2,忽略常数项和对增速影响不大的因子,只保留影响最大的因子,那么该算法的时间复杂度即为O(n^2)。

常见的时间复杂度量级:

  • 常数阶O(1)

  • 对数阶O(logN)

  • 线性阶O(n)

  • 线性对数阶O(nlogN)

  • 平方阶O(n²)

  • 立方阶O(n³)

  • K次方阶O(n^k)

  • 指数阶(2^n)

以上算法时间复杂度中,随着n的增大,f(n)增速越快,说明算法的效率越低。即算法耗费的时间O(1) < O(logN) < O(n) < O(nlogN) < O(n²) < O(n³) < O(n^k) < O(2^n)。

如果想在一个数组中找到一个数,最简单的方法就是循环遍历:

public boolean search(int m) {
    int[] arr = new int[]{3, 5, 7, 1, 2, 6, 4, 9};
    for (int i = 0; i < arr.length; i++) {
        if (m == arr[i]) {
            return true;
        }
    }
    return false;
}

如果要查找的是数是数组的第一个数(本例子中的3),那么只需要一次循环就能找到,时间复杂度为O(1)。但是如果要查找的数在数组最后位置(本例中的9),那么必须要经过arr.length次循环,时间复杂度为O(n),n为数组的长度。那么这段代码代码块的时间复杂度到底是多少呢?

一般在没有特殊说明的情况下,时间复杂度都是指最坏的时间复杂度,因为没有比这更坏的情况了。所以这段代码块的时间复杂度为O(n)。

时间复杂度描述的是算法消耗时间趋势,同理,空间复杂度则是描述算法在运行时临时内存消耗的趋势,一般用 S(n) 来定义,记作S(n)=O(fn)。

至于评价算法的具体好坏,就要具体情况具体分析了。有时我们会拿时间换空间,有时会去拿空间换时间,有时则需要同时考虑时间和空间复杂度。

总之,具体问题具体分析,但是我们一定要理解时间复杂度和空间复杂度的分析过程。

“怎么理解时间复杂度和空间复杂度”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!


网站栏目:怎么理解时间复杂度和空间复杂度
浏览路径:http://pwwzsj.com/article/ieeiod.html