数据结构:时间复杂度(Time Complexity)和空间复杂度(Space Complexity)

目录

什么是时间复杂度?

如何表示时间复杂度?

为什么需要时间复杂度?

用几个例子理解

怎么分析代码的时间复杂度?

什么是空间复杂度?

举例理解


什么是时间复杂度?

时间复杂度是用来衡量一个算法"运行时间随输入规模增长的速度"的指标。

我们关心的是:

➡ 当输入规模 n 越来越大时,程序运行时间变快还是变慢?变慢得有多快?

但注意:

我们不是计算具体运行时间(秒),而是研究增长趋势(数量级)!

比如:

  • 输入 10 个元素花 1ms,100 个元素花 100ms:说明时间增长很快。

  • 输入 10 个元素花 1ms,100 个元素花 2ms:说明增长很慢,很高效。

如何表示时间复杂度?

我们通常用大 O 表示法(Big-O Notation)来表示时间复杂度,比如:

  • O(1) 常数级

  • O(log⁡n)对数级

  • O(n)线性级

  • O(nlog⁡n) 线性对数级

  • O(n^2)平方级

  • O(2^n)、O(n!)指数、阶乘级(非常慢)

这些从快到慢大致排序为:

复制代码
O(1) < O(log n) < O(n) < O(n log n) < O(n^2) < O(2^n) < O(n!)

为什么需要时间复杂度?

能预测程序是否能处理大数据。

  • 比如O(n^2)的程序在 n = 10^5时已经跑不动了;

  • 而 O(nlog⁡n) 在 n = 10^6 时依然很快。

能比较不同算法的效率。

选择排序是 O(n^2),归并排序是 O(nlog⁡n),在大数据面前差别巨大。

用几个例子理解

1. O(1):常数级

cpp 复制代码
int a = 5;
int b = a + 3;

不管你输入多大,只执行几条语句,时间不随输入增长

2. O(n):线性级

cpp 复制代码
for (int i = 0; i < n; i++) {
    cout << i;
}

循环执行 n 次,输入增加一倍,运行时间也大致增加一倍

3. O(n²):平方级

cpp 复制代码
for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        cout << i << j;
    }
}

嵌套循环,每层都跑 n 次,总运行次数为 n×n = n^2

4. O(log n):对数级(如二分查找)

cpp 复制代码
int binarySearch(vector<int>& nums, int target) {
    int l = 0, r = nums.size() - 1;
    while (l <= r) {
        int mid = (l + r) / 2;
        if (nums[mid] == target) return mid;
        else if (nums[mid] < target) l = mid + 1;
        else r = mid - 1;
    }
    return -1;
}

每次把搜索区间减半,只需要约 log⁡2n 次判断。

怎么分析代码的时间复杂度?

你可以遵循以下步骤:

  1. 看循环嵌套层数

    一层是 O(n),两层是 O(n^2),三层是 O(n^3)

  2. 注意递归的调用树

    如归并排序是 T(n)=2T(n/2)+O(n) → O(nlog⁡n)

  3. 看是否有减半、指数增长、全排列等模式


什么是空间复杂度?

空间复杂度(Space Complexity)是衡量一个算法在运行过程中临时占用多少内存空间的指标。

它回答的问题是:

如果输入规模是 n,算法为了运行,需要开辟多大的"额外空间"?

⚠️ 注意:

  • 不包括输入本身所占的空间,我们关心的是额外的空间使用。

  • 就像时间复杂度关注"运算量增长",空间复杂度关注"内存占用增长"。

举例理解

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

cpp 复制代码
int sum = 0;
for (int i = 0; i < n; i++) {
    sum += arr[i];
}

这里只是用了一些变量(sum, i),无论 n 多大,占用空间都是常数级。

2. O(n):线性空间

cpp 复制代码
vector<int> res(n);
for (int i = 0; i < n; i++) {
    res[i] = arr[i] * 2;
}

开了一个和输入一样大的数组 res,所以空间复杂度是 O(n)。

3. O(n²):二维数组

cpp 复制代码
int matrix[n][n];

每个维度都是 n,所以总共是n×n=n2 个元素,空间复杂度是 O(n²)。

4. 递归调用带来的空间

cpp 复制代码
int factorial(int n) {
    if (n == 1) return 1;
    return n * factorial(n - 1);
}

每次递归调用都要占用一次调用栈帧,调用 n 层,就要O(n) 空间。

有些递归算法虽然时间复杂度是 O(n),但如果用了"尾递归"或"迭代替代递归",可以把空间优化到 O(1)。

相关推荐
CSharp精选营4 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假7 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠8 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦15 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠16 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾16 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82116 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q16 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒16 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记16 天前
单项不带头不循环链表
数据结构·链表