时间和空间复杂程度计算规则

时间复杂度和空间复杂度的计算是算法分析的重要部分。以下是详细的计算方法、示例,以及需要注意的要点。


1. 时间复杂度

时间复杂度描述算法执行所需时间随输入规模增长的增长关系,通常用 大 O O O 表示法 来表示,关注输入规模 n n n 的增长率。


1.1 时间复杂度的计算方法

  1. 找到最内层操作

    • 确定算法中执行次数最多的基本操作(如赋值、比较、加法等)。
  2. 统计执行次数

    • 从外到内,计算循环、递归或逻辑分支中基本操作的执行次数。
  3. 保留最高阶

    • 只保留执行次数随输入规模 n n n 增长最快的部分,忽略低次项和常数系数。

1.2 常见时间复杂度

  1. 常数时间: O ( 1 ) O(1) O(1)

    • 不依赖于输入规模,执行次数恒定。
    c 复制代码
    int a = 10;
    a = a + 1; // 常数时间
  2. 线性时间: O ( n ) O(n) O(n)

    • 基本操作执行次数与输入规模 n n n成正比。
    c 复制代码
    for (int i = 0; i < n; i++) {
        printf("%d\n", i); // 执行 n 次
    }
  3. 平方时间: O ( n 2 ) O(n^2) O(n2)

    • 嵌套循环中,每个循环迭代 n n n次,基本操作执行 n 2 n^2 n2次。
    c 复制代码
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            printf("%d, %d\n", i, j); // 执行 n * n 次
        }
    }
  4. 对数时间: O ( log ⁡ n ) O(\log n) O(logn)

    • 规模每次减小一半,通常出现在二分查找等算法中。
    c 复制代码
    while (low <= high) {
        mid = (low + high) / 2;
        if (arr[mid] == target)
            return mid;
        else if (arr[mid] < target)
            low = mid + 1;
        else
            high = mid - 1;
    }
  5. 线性对数时间: O ( n log ⁡ n ) O(n \log n) O(nlogn)

    • 通常出现在分治算法(如归并排序)。
    c 复制代码
    void mergeSort(int arr[], int n) {
        if (n <= 1) return;
        int mid = n / 2;
        mergeSort(left, mid);
        mergeSort(right, n - mid);
        merge(left, right, arr); // 合并操作执行 O(n)
    }
  6. 指数时间: O ( 2 n ) O(2^n) O(2n)

    • 通常出现在递归枚举(如穷举法)。
    c 复制代码
    void subset(int[] arr, int n) {
        if (n == 0) return;
        subset(arr, n - 1);
        subset(arr + [arr[n]], n - 1); // 分成两种选择
    }

1.3 示例:时间复杂度的具体分析

示例 1:
c 复制代码
for (int i = 0; i < n; i++) {
    printf("%d\n", i);
}
  • 基本操作:printf
  • 执行次数: n n n。
  • 时间复杂度: O ( n ) O(n) O(n)。
示例 2:
c 复制代码
for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        printf("%d, %d\n", i, j);
    }
}
  • 基本操作:printf
  • 执行次数:外层循环执行 n n n次,内层循环每次执行 n n n次,总共 n × n = n 2 n \times n = n^2 n×n=n2 次。
  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)。
示例 3:
c 复制代码
int i = 1;
while (i <= n) {
    i *= 2;
}
  • 基本操作:i *= 2
  • 执行次数:每次迭代 i i i乘 2,最多执行 l o g 2 n log_2 n log2n 次。
  • 时间复杂度: O ( log ⁡ n ) O(\log n) O(logn)。

2. 空间复杂度

空间复杂度描述算法运行时使用的额外内存随输入规模增长的关系,也用 大 O 表示法 表示。


2.1 空间复杂度的计算方法

  1. 统计额外变量

    • 计算算法使用的变量、数组、递归栈的大小。
  2. 输入空间不计入

    • 输入数组或数据结构的存储空间不属于额外空间。
  3. 递归调用的栈空间

    • 如果算法有递归,递归栈的深度乘以每层所需空间。

2.2 常见空间复杂度

  1. 常数空间: O ( 1 ) O(1) O(1)

    • 使用固定数量的变量,无论输入规模如何。
    c 复制代码
    int a = 0;
    a++;
  2. 线性空间: O ( n ) O(n) O(n)

    • 使用额外的数组或数据结构,大小与输入规模 n n n成正比。
    c 复制代码
    int* temp = (int*)malloc(n * sizeof(int));
  3. 递归栈空间: O ( n ) O(n) O(n)

    • 深度为 n n n的递归会使用 O ( n ) O(n) O(n) 的栈空间。
    c 复制代码
    void recursive(int n) {
        if (n == 0) return;
        recursive(n - 1);
    }

2.3 示例:空间复杂度的具体分析

示例 1:
c 复制代码
int sum = 0;
for (int i = 0; i < n; i++) {
    sum += i;
}
  • 使用的额外变量:sumi,总共占用固定空间。
  • 空间复杂度: O ( 1 ) O(1) O(1)。
示例 2:
c 复制代码
int* temp = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
    temp[i] = i;
}
  • 使用的额外空间:长度为 n n n的数组 temp
  • 空间复杂度: O ( n ) O(n) O(n)。
示例 3:
c 复制代码
void recursive(int n) {
    if (n == 0) return;
    recursive(n - 1);
}
  • 每次递归调用都会占用一个栈帧。
  • 如果递归深度为 n n n,栈空间总大小为 O ( n ) O(n) O(n)。

3. 时间复杂度和空间复杂度的对比

算法类型 时间复杂度 空间复杂度
直接循环 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)
嵌套循环 O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)
递归算法 O ( 2 n ) O(2^n) O(2n) O ( n ) O(n) O(n)
分治算法 O ( n log ⁡ n ) O(n \log n) O(nlogn) O ( n ) O(n) O(n)
动态规划 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2)

总结

  • 时间复杂度
    • 根据基本操作的执行次数,分析循环、分支、递归的增长趋势。
  • 空间复杂度
    • 根据额外变量、数组、递归栈的大小,估算内存使用的增长关系。

理解和计算复杂度需要结合实际代码逐行分析,尤其要关注循环和递归结构的执行规律。

相关推荐
毕竟是shy哥2 小时前
计算YOLO数据集中每个类的目标数
算法·yolo·机器学习
M78佐菲2 小时前
Linux学习笔记:TCP协议
linux·笔记·学习·tcp/ip·算法
学长毕业设计2 小时前
基于SpringBoot的公益基金管理系统(源码+文档+讲解视频)
java·spring boot·后端
东小西2 小时前
【SAA实战】第 3 篇 · 工具调用全攻略:把业务能力交给 Agent 自己调度
java·后端·spring
东小西2 小时前
【SAA实战】第 4 篇 · Agent 短期记忆:saver 让 Agent 跨轮记得住(threadId 隔离)
java·后端·spring
许彰午2 小时前
22-DataCenter报文序列化
java·低代码·架构·状态模式
2601_962065252 小时前
[MySQL] SQL优化之性能分析
java·sql·mysql
小范同学_3 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
晊晌_h3 小时前
嵌入式从0到精通——数据结构总结[特殊字符]
数据结构·算法·排序算法
我找到地球的支点啦4 小时前
Matlab系列(009) 一CRC循环冗余校验详解
开发语言·数据结构·算法·matlab·信息与通信