数据结构与算法全景:从底层原理到工程实战

本文旨在以极简视角构建数据结构与算法的全景图谱。我们将从最基础的线性结构出发,深入散列与树形世界,直至复杂的图论与特殊结构。重点剖析每种结构的设计哲学、经典算法及其在 MySQL、Spring、Redis、前端等领域的工程实战。

TL;DR

  1. 线性结构:简单高效,适合顺序存储与访问(如数组、队列)。
  2. 树形结构:层级分明,适合海量数据的高效检索与排序(如 B+ 树、红黑树)。
  3. 散列结构:以空间换时间,实现 O(1) 极速查找(如 HashMap)。
  4. 工程哲学:没有最好的数据结构,只有最适合场景的 Trade-off(权衡)。

一、 线性结构:秩序之美

1. 数组 (Array) & 链表 (LinkedList)

  • 核心差异:
    • 数组:连续内存,随机访问 O(1),插入删除 O(n)。
    • 链表:离散内存,随机访问 O(n),插入删除 O(1)。
  • 工程实战:
    • Java ArrayList:底层为数组,适合读多写少。扩容时需拷贝旧数组(耗性能)。
    • React Fiber:底层用链表重构了 Virtual DOM 树,利用链表的“可中断”特性实现时间切片,解决主线程阻塞问题。
    • Redis List:早期用 ZipList(压缩列表)省内存,后改用 QuickList(链表+数组)平衡空间与时间。

2. 栈 (Stack) & 队列 (Queue)

  • 机制:
    • 栈:LIFO(后进先出)。
    • 队列:FIFO(先进先出)。
  • 经典算法:DFS(深度优先搜索,用栈),BFS(广度优先搜索,用队列)。
  • 工程实战:
    • JVM 栈帧:方法调用链天然契合栈结构。
    • 浏览器事件循环:宏任务队列 (MacroTask Queue) 与微任务队列 (MicroTask Queue) 调度异步操作。
    • Spring @Async:线程池的任务队列 (BlockingQueue) 缓冲突发请求。

二、 散列结构:速度极限

1. 哈希表 (Hash Table)

  • 痛点:如何在大规模数据中实现 O(1) 查找?
  • 机制:Hash 函数映射 Key 到数组下标。
  • 挑战:Hash 冲突。
    • 解法:
      • 链地址法 (Separate Chaining):“房间不够,挂个链表” —— 冲突时将元素串成链表挂在该位置下(如 Java HashMap)。
      • 开放寻址法 (Open Addressing):“房间有人,找下一个” —— 冲突时按规则(如线性探测)找下一空位(如 ThreadLocal)。
  • 工程实战:
    • Java HashMap:数组 + 链表 + 红黑树(JDK 8+)。当链表长度 > 8 时转红黑树,防 DoS 攻击。
    • ThreadLocal:使用开放寻址法解决冲突(线性探测),因为 ThreadLocalMap 通常较小且需快速清理。
    • Redis Dict:渐进式 Rehash,避免扩容时阻塞主线程。

三、 树形结构:分层与索引

1. 二叉搜索树 (BST) -> 平衡树 (AVL/红黑树)

  • 痛点:普通 BST 易退化为链表 O(n)。
  • 机制:通过旋转保持树的高度平衡,保证查找 O(log n)。
  • 工程实战:
    • Java TreeMap:基于红黑树,保证 Key 有序。
    • Linux CFS 调度器:用红黑树管理进程 vruntime,快速选出最需 CPU 的进程。
    • Epoll:内核用红黑树管理海量监听的 Socket FD。

2. B 树 / B+ 树

  • 痛点:磁盘 IO 极慢,红黑树树高过高导致 IO 次数多。
  • 机制:多路平衡查找树,“矮胖”结构,节点存储更多数据,利用磁盘预读。
  • 工程实战:
    • MySQL InnoDB:使用 B+ 树。
      • 聚簇索引:叶子节点存完整行数据。
      • 非聚簇索引:叶子节点存主键 ID(需回表)。
      • 优势:范围查询极快(叶子节点有双向指针连接)。

3. 堆 (Heap)

  • 机制:完全二叉树,父节点总是大于(或小于)子节点。
  • 工程实战:
    • 优先队列 (PriorityQueue):基于小顶堆实现。
    • 定时器 (Timer/DelayQueue):堆顶即最近要执行的任务,无需扫描全表。

四、 图结构:连接与网络

1. 图 (Graph)

  • 表示:邻接矩阵(稠密图)、邻接表(稀疏图)。
  • 经典算法:Dijkstra (最短路径)、Topological Sort (拓扑排序)。
  • 工程实战:
    • Spring Bean 依赖:检测循环依赖(DAG 有向无环图检测)。
    • 微服务调用链:Zipkin/SkyWalking 拓扑图生成。
    • 死锁检测:资源分配图中有环即死锁。

五、 特殊结构:极致优化

1. 跳表 (SkipList)

  • 机制:链表 + 多级索引。以空间换时间,实现 O(log n) 查找。
  • 对比:比红黑树实现简单,并发支持更好。
  • 工程实战:
    • Redis ZSet:有序集合底层核心。支持范围查询,性能媲美平衡树。

2. 布隆过滤器 (Bloom Filter)

  • 机制:多个 Hash 函数 + 位图 (BitMap)。
  • 特性:判断“不存在”一定准,判断“存在”可能有误判。
  • 工程实战:
    • 缓存穿透防护:请求打到 DB 前先查布隆过滤器,若不存在直接返回。
    • 爬虫 URL 去重:海量 URL 快速去重,极省内存。

六、 总结与思考

数据结构的演进史,本质是场景倒逼设计的历史。

  • 读多写少 → 数组/B+ 树。
  • 写多读少 → 链表/LSM Tree (Log-Structured Merge Tree, HBase/RocksDB 核心)。
  • 极致查找 → Hash。
  • 有序查找 → 红黑树/跳表。

掌握这些底层原理,在面对“MySQL 为什么要用 B+ 树而不是红黑树”、“Redis ZSet 为什么用跳表”等架构抉择时,方能洞若观火。


数据结构与算法全景:从底层原理到工程实战
https://blog.baoyanfudao.com/tech/数据结构与算法全景:从底层原理到工程实战/
作者
XuYafei
发布于
2018年9月1日
许可协议