数据结构自学笔记(二):时间复杂度与空间复杂度

时间复杂度和空间复杂度知识点

一、知识点描述

  1. 时间复杂度

    • 核心定义:描述算法时间开销随问题规模nnn增长的趋势,用大O符号表示(忽略常数、低阶项和系数)。
    • 大O规则
      • 只看最高阶项(如O(n2+n)→O(n2)O(n^2 + n) \rightarrow O(n^2)O(n2+n)O(n2))。
      • 忽略系数(如O(5n3)→O(n3)O(5n^3) \rightarrow O(n^3)O(5n3)O(n3))。
      • 常数项记为O(1)O(1)O(1)(如O(100)→O(1)O(100) \rightarrow O(1)O(100)O(1))。
    • 常见时间复杂度(从小到大排序)
      • O(1)O(1)O(1):常数时间,如数组随机访问。
      • O(log⁡n)O(\log n)O(logn):对数时间,如二分查找。
      • O(n)O(n)O(n):线性时间,如数组遍历。
      • O(nlog⁡n)O(n \log n)O(nlogn):线性对数时间,如归并排序。
      • O(n2)O(n^2)O(n2):平方时间,如冒泡排序。
      • O(2n)O(2^n)O(2n):指数时间,如递归斐波那契。
      • O(n!)O(n!)O(n!):阶乘时间,如全排列枚举。
    • 求解步骤
      • 定位基本操作(执行次数最多的语句)。
      • 计算执行次数f(n)f(n)f(n)(分析nnn的影响)。
      • 化简为大O(保留最高阶项)。
    • 示例关键点
      • 遍历数组求和:基本操作执行nnn次,f(n)=n→O(n)f(n) = n \rightarrow O(n)f(n)=nO(n)
      • 嵌套循环:基本操作执行n2n^2n2次,f(n)=n2→O(n2)f(n) = n^2 \rightarrow O(n^2)f(n)=n2O(n2)
      • 二分查找:每次规模减半,执行约log⁡2n\log_2 nlog2n次,f(n)=log⁡n→O(log⁡n)f(n) = \log n \rightarrow O(\log n)f(n)=lognO(logn)
  2. 空间复杂度

    • 核心定义:描述算法额外空间开销(不包括输入数据)随nnn增长的趋势,用大O符号表示。
    • 原地工作:额外空间为常量时,空间复杂度为O(1)O(1)O(1)
    • 常见空间复杂度
      • O(1)O(1)O(1):原地工作,如冒泡排序。
      • O(n)O(n)O(n):线性空间,如新建数组或递归深度nnn
      • O(n2)O(n^2)O(n2):平方空间,如新建n×nn \times nn×n矩阵。
    • 求解步骤
      • 分析额外空间(变量、数据结构、递归栈等)。
      • 找出空间与nnn的关系f(n)f(n)f(n)
      • 化简为大O(保留主导项)。
    • 示例关键点
      • 冒泡排序:仅用1个临时变量,f(n)=1→O(1)f(n) = 1 \rightarrow O(1)f(n)=1O(1)
      • 新建数组:申请nnn个元素空间,f(n)=n→O(n)f(n) = n \rightarrow O(n)f(n)=nO(n)
      • 递归阶乘:递归深度nnn,栈空间f(n)=n→O(n)f(n) = n \rightarrow O(n)f(n)=nO(n)
  3. 时间与空间权衡

    • 核心思想:两者均关注“趋势”,而非精确值;设计算法时需根据场景取舍。
    • 权衡策略
      • 时间换空间:如链表(插入/删除快,但遍历慢)。
      • 空间换时间:如哈希表(用额外空间加速查找)。
    • 设计原则:对时间敏感场景优先优化时间复杂度,对空间敏感场景优先优化空间复杂度。
  4. 学习技巧

    • 推导方法:从代码出发,定位基本操作和额外空间,逐步推导复杂度。
    • 对比分析:比较不同算法的复杂度(如冒泡排序O(n2)O(n^2)O(n2) vs 归并排序O(nlog⁡n)O(n \log n)O(nlogn)),理解效率差异。
    • 实践应用:结合实际问题(如大数据量选算法),强化复杂度感知。
  5. 示例

示例1:遍历数组求和(O(n)O(n)O(n)

int sum = 0;
for(int i=0; i<n; i++){
    sum += arr[i]; // 基本操作,执行n次 → f(n)=n → O(n)
}

示例2:嵌套循环(O(n2)O(n^2)O(n2)

for(int i=0; i<n; i++){
    for(int j=0; j<n; j++){
        printf("%d", arr[i][j]); // 执行n²次 → f(n)=n² → O(n²)
    }
}

示例3:二分查找(O(log⁡n)O(\log n)O(logn)

int binarySearch(int arr[], int n, int target){
    int left=0, right=n-1;
    while(left <= right){
        int mid = (left+right)/2; // 每次规模减半,执行≈log₂n次 → O(logn)
        ...
    }
}

二、空间复杂度

1. 核心定义

  • 描述:算法额外空间开销(不包括输入数据)随nnn增长的趋势。
  • 原地工作:额外空间为常量时,空间复杂度O(1)O(1)O(1)

2. 常见空间复杂度

复杂度 含义 典型场景
O(1)O(1)O(1) 原地工作 冒泡排序
O(n)O(n)O(n) 线性空间 新建数组
O(n2)O(n^2)O(n2) 平方空间 新建二维矩阵

3. 求解步骤

  1. 分析额外空间:统计算法内部空间(如变量、数据结构、递归栈)。
  2. 找出关系:得到空间表达式f(n)f(n)f(n)
  3. 化简为大O:保留主导项。

4. 示例

示例1:冒泡排序(O(1)O(1)O(1)

void bubbleSort(int arr[], int n){
    for(int i=0; i<n; i++){
        for(int j=0; j<n-i-1; j++){
            if(arr[j]>arr[j+1]){
                int temp = arr[j]; // 仅1个临时变量 → f(n)=1 → O(1)
                ...
            }
        }
    }
}

示例2:新建数组(O(n)O(n)O(n)

int* squareArray(int arr[], int n){
    int* res = new int[n]; // 申请n个元素空间 → f(n)=n → O(n)
    ...
}

示例3:递归阶乘(O(n)O(n)O(n)

int factorial(int n){
    if(n==0) return 1;
    return n * factorial(n-1); // 递归深度n → 栈空间f(n)=n → O(n)
}

三、时间与空间权衡

1. 核心思想

  • 关注“趋势”,而非精确值;设计时需取舍(如时间敏感优先优化时间复杂度)。

2. 权衡策略

  • 时间换空间:链表(插入/删除快,遍历慢)。
  • 空间换时间:哈希表(额外空间加速查找)。

四、学习技巧

  1. 推导练习:从代码定位基本操作和额外空间,推导f(n)f(n)f(n)并化简。
  2. 对比算法:比较复杂度差异(如冒泡O(n2)O(n^2)O(n2) vs 归并O(nlog⁡n)O(n \log n)O(nlogn))。
  3. 实际问题应用:针对场景选择算法(如大数据量优先O(nlog⁡n)O(n \log n)O(nlogn))。

你可能感兴趣的:(数据结构自学笔记(二):时间复杂度与空间复杂度)