[数据结构]-02时间空间复杂度

算法

算法是解决特定问题求解步骤的描述,在计算机中表现为指定的有限序列,并且每条指令表示一个或多个操作。

时间复杂度

度量算法执行时间的两种方法:

  • 事后统计的方法:编写算法程序后再进行分析
    • 需要实际运行程序才能对算法的性能进行评测;
    • 算法的运算性能依赖于计算机的硬件、软件等环境因素,只有在同一机器的相同状态下,才能比较算法的优劣。
  • 事前估算的方法:通过分析算法的时间复杂度来判断算法的优劣。

时间频度

一个算法中的语句执行次数称为语句频度或时间频度,记为 T ( n ) T(n)

  • 算法花费的时间与算法中语句的执行次数成正比例;
  • 算法中语句执行次数多,它花费时间越长。

例如计算 1-n 的和:


        // 方式1:使用for循环
        int total = 0; // 执行一次
        for (int i = 1; i <= n; i++) { // 执行 n+1 次
            total += i; // 执行 n 次
        }

        // 方式2:公式直接计算
        int total = 0; // 执行一次
        total = (1 + n) * n / 2; // 执行一次

方式 1 共执行了 1 + n + 1 + n = 2 n + 2 1+n+1+n=2n+2 次,故 T ( n ) = 2 n + 2 T(n)=2n+2
方式 2 共执行了 1 + 1 = 2 1+1=2 次,故 T ( n ) = 2 T(n)=2
因此方式 2 的时间频度更小。

忽略常数项

在这里插入图片描述
在这里插入图片描述

  • T ( n ) = 2 n + 20 T(n)=2n+20 T 1 ( n ) = 2 n T_1(n)=2n 随着 n n 增大,两条函数曲线无限接近,常数项 20 可忽略。
  • T ( n ) = 3 n + 10 T(n)=3n+10 T 1 ( n ) = 3 n T_1(n)=3n 随着 n n 增大,两条函数曲线无限接近,常数项 10 可忽略。

忽略低次项

在这里插入图片描述
在这里插入图片描述

  • T ( n ) = 2 n 2 + 3 n + 10 T(n)=2n^2+3n+10 T 1 ( n ) = 2 n 2 T_1(n)=2n^2 随着 n n 增大,两条函数曲线无限接近,低次项 3 n + 10 3n+10 可忽略。
  • T ( n ) = n 2 + 5 n + 20 T(n)=n^2+5n+20 T 1 ( n ) = n 2 T_1(n)=n^2 随着 n n 增大,两条函数曲线无限接近,低次项 5 n + 20 5n+20 可忽略。

忽略系数

在这里插入图片描述
在这里插入图片描述

  • T ( n ) = 5 n 2 + 7 n T(n)=5n^2+7n T 1 ( n ) = 3 n 2 + 2 n T_1(n)=3n^2 + 2n 随着 n n 增大,两条函数曲线无限接近, T ( n ) T(n) 系数 5 与 T 1 ( n ) T_1(n) 系数 3 可忽略。
  • T ( n ) = n 3 + 5 n T(n)=n^3+5n T 1 ( n ) = 6 n 3 + 4 n T_1(n)=6n^3 + 4n 随着 n n 增大,两条函数曲线无限接近, T ( n ) T(n) 系数 1 与 T 1 ( n ) T_1(n) 系数 6 可忽略。

时间复杂度

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

时间复杂度的特点
不同的 T ( n ) T(n) ,时间复杂度可能相同。 如: T ( n ) = n 2 + 7 n + 6 T(n)=n^2+7n+6 T ( n ) = 3 n 2 + 2 n + 2 T(n)=3n^2+2n+2 T ( n ) T(n) 不同,但时间复杂度相同,都为 O ( n 2 ) O(n^2)

计算时间复杂度的方法:

  • 用常数 1 代替运行时间中的所有加法常数: T ( n ) = n 2 + 7 n + 6 = > T ( n ) = n 2 + 7 n + 1 T(n)=n^2+7n+6 => T(n)=n^2+7n+1
  • 修改后的运行次数函数中,只保留最高阶项: T ( n ) = n 2 + 7 n + 1 = > T ( n ) = n 2 T(n)=n^2+7n+1 => T(n)=n^2
  • 去除最高阶项的系数: T ( n ) = n 2 = > T ( n ) = n 2 = > O ( n 2 ) T(n)=n^2 => T(n)=n^2 => O(n^2)

常见的时间复杂度:

  • 常数阶 O ( 1 ) O(1)
  • 对数阶 O ( log 2 n ) O(\log_2n)
  • 线性阶 O ( n ) O(n)
  • 线性对数阶 O ( n log 2 n ) O(n\log_2n)
  • 平方阶 O ( n 2 ) O(n^2)
  • 立方阶 O ( n 3 ) O(n^3)
  • k 次方阶 O ( n k ) O(n^k)
  • 指数阶 O ( 2 n ) O(2^n)

常见的算法时间复杂度由小到大依次为: O ( 1 ) < O ( log 2 n ) < O ( n ) < O ( n log 2 n ) < O ( n 2 ) < O ( n 3 ) < O ( n k ) < O ( 2 n ) Ο(1)<Ο(\log_2n)<Ο(n)<Ο(n\log_2n)<Ο(n^2)<Ο(n^3)<Ο(n^k)<Ο(2^n)
随着问题规模 n n 的不断增大,时间复杂度不断增大,算法的执行效率越低。
在这里插入图片描述

常数阶 O(1)

无论代码执行多少行,只要没有结构等复杂结构,则该段代码的时间复杂度就是 O ( 1 ) O(1)

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

解释说明:上述代码在执行的时候,消耗的时间并不随某个变量的增长而增长,即无论该类代码有多少行,都可以用 O ( 1 ) O(1) 表示其时间复杂度。

线性阶 O(n)

        for (i = 1; i <= n; ++i) {
            j = i;
            j++;
        }

解释说明:for 循环中的代码会执行 n n 遍,因此它消耗的时间是随着 n n 的变化而变化的,因此该类代码的时间复杂度用 O ( n ) O(n) 标识。

对数阶 O(log2n)

        int i = 1;
        while (i < n) {
            i = i * 2;

        }

解释说明:在 while 循环中,每次都将 i i 乘以 2,乘完之后, i i 距离 n n 就越来越近。假设循环 x x 次之后, i i 就大于 2 了,此时循环退出,即 2 的 x x 次方等于 n n
x = log 2 n x=\log_2n 。因此该代码的复杂度为 O ( log 2 n ) O(\log_2n) O ( log 2 n ) O(\log_2n) 中的底数 2 是根据代码变化的,若i=i*3,则是 O ( log 3 n ) O(\log_3n)

对数阶 O(nlogn)

        for (i = 1; i <= n; ++i) {
            i = 1;
            while (i < n) {
                i = i * 2;
            }
        }

解释说明:将时间复杂度为 O ( l o g n ) O(logn) 的代码循环 n n 遍,其时间复杂度即变为 n O ( l o g n ) n*O(logn) ,即 O ( n l o g n ) O(nlogn)

平方阶 O(n^2)

        for (i = 1; i <= n; i++) {
            for (j = 1; j <= n; j++) {
                a = i + j;
            }
        }

解释说明:将时间复杂度为 O ( n ) O(n) 的代码再嵌套循环一遍,时间复杂度则变为 O ( n 2 ) O(n^2)

平均时间复杂度和最坏时间复杂度

  • 所有可能的输入实例均以等概率出现的情况下,该算法的运行时间,称为平均时间复杂度。
  • 最坏情况下的时间复杂度称最坏时间复杂度。
    一般讨论的时间复杂度均是最坏情况下的时间复杂度。最坏情况下的时间复杂度是算法在任何输入实例上运行时间的上限,保证了算法的运行时间不会比最坏情况更长。

平均时间复杂度和最坏时间复杂度是否一致与具体的算法有关。

空间复杂度

算法所耗费的存储空间称为空间复杂度。

算法所占用的空间有哪些?

  • 算法本身占用的空间,输入、输出、指令、常数、变量等
  • 算法要使用的辅助空间

空间复杂度特点:

  • 对一个算法在运行过程中临时占用存储空间大小的量度。
  • 空间复杂度是关于 n n 的函数,随着 n n 的增大,占用的存储越大。

参考

  • 《Java数据结构与算法》 韩顺平
发布了19 篇原创文章 · 获赞 0 · 访问量 764

猜你喜欢

转载自blog.csdn.net/qq_39953750/article/details/103888473