【学习笔记】算法学习01:复杂度分析

本文详细探讨了算法的时间复杂度和空间复杂度,包括它们的定义、计算方法、常见类型以及最差、最佳和平均值的含义。特别强调了时间复杂度分析的特点,以及在实际应用中的考量因素,如空间复杂度中的栈帧空间和递归函数的影响。
摘要由CSDN通过智能技术生成

学习地址Hello算法:https://www.hello-algo.com/

一、复杂度分析

1.1 时间复杂度

时间复杂度分析统计的不是算法运行时间,而是算法运行时间随着数据量变大时的增长趋势

1.1.1 时间复杂度分析有哪些特点?

  • 时间复杂度能够有效评估算法效率。输入的数据越大,时间复杂度更优的算法,效率更高。
  • 时间复杂度的推算方法更简便。可以简单地将所有计算操作的执行时间视为相同的“单位时间”,从而将“计算操作运行时间统计”简化为“计算操作数量统计”
  • 时间复杂度也存在一定的局限性。时间复杂度不能等同于实际运行时间差别很大,在实际情况下,我们很难仅凭时间复杂度判断算法效率的高低。尽管存在上述问题,复杂度分析仍然是评判算法效率最有效且常用的方法。

1.1.2 计算方法:

  • 第一步:统计操作数量——操作数量 T(n) 中的各种系数、常数项都可以忽略循环嵌套时使用乘法

  • 第二步:判断渐近上界——时间复杂度由 T(n) 中最高阶的项来决定。这是因为在 n 趋于无穷大时,最高阶的项将发挥主导作用,其他项的影响都可以忽略。

    image-20240221103732655

    函数渐近上界

    函数的渐近上界

1.1.3 常见类型的时间复杂度:

  1. 即使操作数量 size 可能很大,操作数量与输入数据大小 n 无关,时间复杂度仍为 常数阶O(1)
  2. 操作数量相对于输入数据大小 n 以线性级别增长 线性阶 O(n);比如遍历数组和遍历链表等操作
  3. O(n2) 平方阶通常出现在嵌套循环中。比如冒泡
  4. 生物学的“细胞分裂”是指数阶增长的典型例子,时间复杂度为 指数阶O(2n) 。对于数据规模较大的问题,指数阶是不可接受的,通常需要使用动态规划或贪心算法等来解决。
  5. 与指数阶相反,对数阶反映了“每轮缩减到一半”的情况。时间复杂度为 O(log2⁡n) ,简记为 O(log⁡n)

image-20240221103815310

常见的时间复杂度类型

1.1.4 最差、最佳、平均时间复杂度

算法的时间效率往往不是固定的,而是与输入数据的分布有关。同样的一个算法会根据输入的数据不同,而体现不同的运算效率。

  • 输入最适合的数据时,达到最佳时间复杂度 Ω(1)
  • 输入的数据最差时,达到最差时间复杂度 O(n)

值得说明的是,我们在实际中很少使用最佳时间复杂度,因为通常只有在很小概率下才能达到,可能会带来一定的误导性。而最差时间复杂度更为实用,因为它给出了一个效率安全值,让我们可以放心地使用算法。

相比之下,平均时间复杂度可以体现算法在随机输入数据下的运行效率,用 Θ 记号来表示。

但对于较为复杂的算法,计算平均时间复杂度往往比较困难,因为很难分析出在数据分布下的整体数学期望。在这种情况下,我们通常使用最差时间复杂度作为算法效率的评判标准


1.2 空间复杂度

1.2.1 算法相关空间

  • 输入空间:用于存储算法的输入数据。
  • 暂存空间:用于存储算法在运行过程中的变量、对象、函数上下文等数据。
    • 暂存数据:用于保存算法运行过程中的各种常量、变量、对象等。
    • 栈帧空间:用于保存调用函数的上下文数据。系统在每次调用函数时都会在栈顶部创建一个栈帧,函数返回后,栈帧空间会被释放。
    • 指令空间:用于保存编译后的程序指令,在实际统计中通常忽略不计。
  • 输出空间:用于存储算法的输出数据。
/* 类 */
class Node {
    int val;
    Node next;
    Node(int x) { val = x; }
}

/* 函数 */
int function() {
    // 执行某些操作...
    return 0;
}

int algorithm(int n) {        // 输入数据
    final int a = 0;          // 暂存数据(常量)
    int b = 0;                // 暂存数据(变量)
    Node node = new Node(0);  // 暂存数据(对象)
    int c = function();       // 栈帧空间(调用函数)
    return a + b + c;         // 输出数据
}

一般情况下,空间复杂度的统计范围是“暂存空间”加上“输出空间”。所以在分析一段程序的空间复杂度时,我们通常统计暂存数据、栈帧空间和输出数据三部分

image-20240221104324312

1.2.2 推算方法

空间复杂度的推算方法与时间复杂度大致相同,只需将统计对象从“操作数量”转为“使用空间大小”。

而与时间复杂度不同的是,我们通常只关注最差空间复杂度。“最差”有两层含义。

  • 以最差输入数据为准
  • 以算法运行中的峰值内存为准

在递归函数中,需要注意统计栈帧空间

  • 循环loop()的时间复杂度为 O(n) ,空间复杂度 O(1)
  • 递归函数 recur() 虽然时间复杂度为 O(n) ,但在运行过程中会同时存在 n 个未返回的 结果recur() ,从而占用 O(n) 的栈帧空间。

1.2.3 常见的类型

  1. 常量、变量、对象占用 O(1) 空间
  2. 循环中的变量和函数占用 O(1) 空间
  3. 递归中的变量和函数占用 O(n) 空间
  4. 长度为 n 的数组/列表/哈希表占用 O(n) 空间
  5. 矩阵、二维列表占用 O(n2) 空间
  6. 层数为 n 的“满二叉树”的节点数量为 2n−1 ,占用 O(2n) 空间:
  7. 常用于分治算法,占用O(log⁡n) 的栈帧空间,

image-20240221110041530

常见的空间复杂度类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xcong_Zhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值