【数据结构】-复杂度

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


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),但需考虑哈希冲突。
相关推荐
XiYang-DING1 小时前
【Java SE】JVM字符串常量池:位置、创建流程、对象个数与 `intern()`
java·开发语言·jvm
222you2 小时前
JUC当中的几个计数类
java·开发语言
水月清辉2 小时前
利用python生成一个终极复杂动画:跳动小红心 ✨
开发语言·python
xdl25992 小时前
如何快速搭建简单SpringBoot项目网页
java·spring boot·intellij-idea
小菜鸡桃蛋狗2 小时前
C++——类和对象(中)
开发语言·c++
暮光6292 小时前
通过python启动参数配置ros参数
开发语言·python
k-l.2 小时前
【通过jdbc连接到kingbase数据库插入10w数据】
java·数据库
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于java的书店用户管理系统的设计与实现为例,包含答辩的问题和答案
java·开发语言
晚枫歌F2 小时前
线程池的理解使用以及代码详解
数据结构