【数据结构】-复杂度

在数据结构中,复杂度(通常指时间复杂度和空间复杂度)是衡量算法效率的核心指标,用于分析算法在不同输入规模下的资源消耗情况。


1. 时间复杂度(Time Complexity)

衡量算法执行所需的操作次数(或时间)随输入规模 ( n ) 的增长趋势。常用 大O符号(O) 表示最坏情况下的上界。

常见时间复杂度(从低到高)

  • O(1) :常数时间
    • 操作与输入规模无关(如数组访问 arr[0])。
  • O(log n) :对数时间
    • 每次操作将问题规模减半(如二分查找、平衡二叉树操作)。
  • O(n) :线性时间
    • 操作次数与输入规模成正比(如遍历数组、链表)。
  • O(n log n) :线性对数时间
    • 分治算法的典型复杂度(如归并排序、快速排序)。
  • O(n²) :平方时间
    • 嵌套循环(如冒泡排序、选择排序)。
  • O(2ⁿ) :指数时间
    • 暴力搜索(如子集生成)。
  • O(n!) :阶乘时间
    • 全排列问题(如旅行商问题的暴力解法)。
示例
  • 线性搜索:O(n)(最坏需遍历整个数组)。
  • 二分查找:O(log n)(每次排除一半元素)。
  • 快速排序:平均 O(n log n),最坏 O(n²)(当数组已有序时)。

2. 空间复杂度(Space Complexity)

衡量算法执行过程中占用的额外存储空间随输入规模 ( n ) 的增长趋势。

常见空间复杂度

  • O(1) :常数空间
    • 仅使用固定数量的变量(如交换两个数的值)。
  • O(n) :线性空间
    • 需要存储与输入规模成正比的数据(如哈希表、递归栈)。
  • O(n²) :平方空间
    • 存储二维数据结构(如动态规划的二维表格)。
示例
  • 迭代实现:通常 O(1) 空间(如迭代版斐波那契数列)。
  • 递归实现:可能 O(n) 空间(如递归版斐波那契数列,因递归栈深度为 ( n ))。
  • 归并排序:O(n) 空间(需额外数组存储中间结果)。

3. 复杂度分析的关键点

  1. 最坏情况 vs 平均情况
    • 大O符号通常表示最坏情况(如快速排序的 O(n²)),但有时也分析平均情况(如快速排序的 O(n log n))。
  2. 忽略常数和低阶项
    • O(3n + 2) 简化为 O(n),O(n² + n) 简化为 O(n²)。
  3. 递归算法的复杂度
    • 使用递归树或主定理(Master Theorem)分析(如二分查找的递归式 ( T(n) = 2T(n/2) + O(1) ) 解为 O(n log n))。

4. 数据结构与复杂度的关系

不同数据结构的操作复杂度差异显著,选择时需权衡:

操作 数组 链表 哈希表 二叉搜索树 堆(优先队列)
访问元素 O(1) O(n) O(1) O(log n) O(1)(取极值)
插入/删除 O(n) O(1) O(1) O(log n) O(log n)
搜索 O(n) O(n) O(1) O(log n) O(n)

5. 实际应用中的优化

  • 时间换空间:如用哈希表缓存结果(空间 O(n) 换搜索 O(1))。
  • 空间换时间:如动态规划预计算子问题(空间 O(n²) 换时间 O(n²))。
  • 算法选择:根据问题规模选择合适算法(如小规模用插入排序 O(n²),大规模用快速排序 O(n log n))。

总结

  • 时间复杂度:关注操作次数随 ( n ) 的增长趋势。
  • 空间复杂度:关注额外存储空间的需求。
  • 选择数据结构:根据操作频率(如频繁搜索用哈希表,频繁插入用链表)。

以下是常见数据结构及其核心操作的 时间复杂度空间复杂度 的整理表格,按 线性表、串、堆栈、树、图 分类,方便直观记忆:


1. 线性表(数组 & 链表)

操作 数组(静态) 数组(动态扩容) 单链表 双向链表
访问元素 O(1) O(1) O(n) O(n)
搜索元素 O(n) O(n) O(n) O(n)
头部插入 O(n)(需移动) O(n)(可能扩容) O(1) O(1)
尾部插入 O(1) O(1)(均摊) O(n) O(1)
任意位置插入 O(n) O(n) O(n) O(n)
头部删除 O(n)(需移动) O(n)(可能扩容) O(1) O(1)
尾部删除 O(1) O(1)(均摊) O(n) O(1)
空间复杂度 O(n) O(n)(可能扩容) O(n) O(n)

2. 串(字符串)

操作 朴素匹配(Brute-Force) KMP算法 Boyer-Moore算法
搜索子串 O(n×m)(最坏) O(n+m) O(n/m)(最好)
空间复杂度 O(1) O(m) O(m)(预处理表)

  • ( n ) 为主串长度,( m ) 为子串长度。
  • KMP 和 Boyer-Moore 是高效字符串匹配算法。

3. 堆栈(Stack)

操作 数组实现 链表实现
压栈(Push) O(1)(均摊) O(1)
弹栈(Pop) O(1) O(1)
查看栈顶 O(1) O(1)
空间复杂度 O(n) O(n)

4. 队列(Queue)

操作 数组实现(循环队列) 链表实现
入队(Enqueue) O(1)(均摊) O(1)
出队(Dequeue) O(1) O(1)
查看队首 O(1) O(1)
空间复杂度 O(n) O(n)

5. 树(Tree)

二叉搜索树(BST)
操作 平均情况 最坏情况(退化为链表)
搜索 O(log n) O(n)
插入 O(log n) O(n)
删除 O(log n) O(n)
空间复杂度 O(n) O(n)
平衡二叉搜索树(AVL/红黑树)
操作 所有情况
搜索 O(log n)
插入 O(log n)
删除 O(log n)
空间复杂度 O(n)
堆(优先队列)
操作 二叉堆(数组实现)
插入(Insert) O(log n)
删除极值(Extract-Min/Max) O(log n)
查看极值 O(1)
建堆(Heapify) O(n)
空间复杂度 O(n)

6. 图(Graph)

邻接矩阵表示
操作 时间复杂度 空间复杂度
访问顶点 O(1) O(n²)
访问边 O(1)
添加/删除顶点 O(n)
添加/删除边 O(1)
邻接表表示
操作 时间复杂度 空间复杂度
访问顶点 O(1) O(n + m)
访问边 O(deg(v))(顶点 ( v ) 的度)
添加/删除顶点 O(1)(链表实现)
添加/删除边 O(1)(链表实现)
图遍历算法
算法 时间复杂度(邻接表) 空间复杂度
DFS(深度优先) O(n + m) O(n)(递归栈)
BFS(广度优先) O(n + m) O(n)(队列)
最短路径算法
算法 时间复杂度(邻接表) 空间复杂度
Dijkstra(普通队列) O(nm)(最坏) O(n)
Dijkstra(优先队列) O((n+m) log n) O(n)
Bellman-Ford O(nm) O(n)
Floyd-Warshall O(n³) O(n²)
最小生成树算法
算法 时间复杂度(邻接表) 空间复杂度
Prim(普通队列) O(nm)(最坏) O(n)
Prim(优先队列) O((n+m) log n) O(n)
Kruskal O(m log m)(排序边) O(n + m)

总结表格(精简版)

数据结构 核心操作 时间复杂度(平均/最坏) 空间复杂度
数组 访问/修改 O(1) O(n)
链表 插入/删除(头部) O(1) O(n)
二叉搜索树 搜索/插入/删除 O(log n)/O(n) O(n)
平衡树 搜索/插入/删除 O(log n) O(n)
插入/删除极值 O(log n) O(n)
哈希表 搜索/插入/删除 O(1)(均摊) O(n)
图(邻接表) 遍历(DFS/BFS) O(n + m) O(n)
Dijkstra 最短路径 O((n+m) log n) O(n)

记忆技巧

  1. 线性结构(数组/链表):操作与 ( n ) 成正比(O(n) 或 O(1))。
  2. 树结构:平衡时为 O(log n),退化为链表时为 O(n)。
  3. 图算法:遍历和最短路径通常为 O(n + m),优先队列优化可降复杂度。
  4. 哈希表:均摊 O(1),但需考虑哈希冲突。
相关推荐
小李子呢02112 分钟前
前端八股JS---ES6新增内容
开发语言·javascript·ecmascript
yaoxin5211236 分钟前
381. Java IO API - 控制文件树遍历流程
java·开发语言
计算机安禾6 分钟前
【数据结构与算法】第45篇:跳跃表(Skip List)
c语言·数据结构·算法·list·排序算法·图论·visual studio
SimonKing7 分钟前
OpenCode 20 个斜杠命令,90% 的人只用过 3 个
java·后端·程序员
尽兴-8 分钟前
Spring与Dubbo整合原理与源码分析
java·spring·dubbo·enabledubbo
Gopher_HBo8 分钟前
BlockingQueue详解
java·后端
白露与泡影8 分钟前
为什么在IDEA使用@Autowired会报黄?
java·ide·intellij-idea
zhaoshuzhaoshu10 分钟前
Python 语法之控制结构详解
开发语言·python
我登哥MVP11 分钟前
【Spring6笔记】 - 15 - Spring中的八大设计模式
java·spring boot·笔记·spring·设计模式·intellij-idea
咚为12 分钟前
深入理解 Rust 的静态分发与动态分发:从 `impl Trait` 到 `dyn Trait`
开发语言·后端·rust