04 — 算法与数据结构

核心规律:选择合适的结构,是性能和可维护性的基础 一句话:没有最好的数据结构,只有最适合场景的数据结构


一、核心规律

1.1 数据结构选择决策树

flowchart TD
    A["需要数据存储?"] --> B{"需要有序吗?"}
    B -->|是| C{"需要快速查找吗?"}
    B -->|否| D["数组/列表"]
    C -->|是| E["哈希表 O(1)"]
    C -->|否| F["有序数组/链表"]
    
    G["需要范围查询?"] --> H["B+树/红黑树"]
    I["需要层级关系?"] --> J["树/图"]
    K["需要最短路径?"] --> L["图算法"]
    
    style E fill:#e8f5e9
    style H fill:#fff3e0
    style J fill:#e3f2fd

1.2 时间复杂度速查

pie title 常见算法时间复杂度分布
    "O(1) 常数" : 10
    "O(log n) 对数" : 20
    "O(n) 线性" : 25
    "O(n log n) 线性对数" : 25
    "O(n2) 平方" : 15
    "O(2n) 指数" : 5
复杂度名称典型算法
O(1)常数哈希查找、数组索引
O(log n)对数二分查找
O(n)线性线性查找、遍历
O(n log n)线性对数快速排序、归并排序
O(n²)平方冒泡排序、双重循环

二、常用数据结构

2.1 数组与链表

特性数组链表
内存连续离散
随机访问O(1) ✅O(n) ❌
插入删除O(n) ❌O(1) ✅
PHP实现arraySPL SplDoublyLinkedList

2.2 哈希表

哈希表 = 数组 + 哈希函数

Key → 哈希函数 → 索引 → 值

冲突解决:
├── 链地址法:每个桶挂链表
└── 开放寻址:找下一个空位

PHP中的哈希表: PHP的array底层就是哈希表

2.3 栈与队列

结构特点应用场景
后进先出(LIFO)函数调用栈、括号匹配
队列先进先出(FIFO)消息队列、广度优先搜索
双端队列两端都可进出滑动窗口、回文判断

2.4 树

flowchart LR
    A["二叉树"] --> B["二叉搜索树<br/>左<根<右"]
    B --> C["平衡二叉树<br/>AVL/红黑树"]
    B --> D["B+树<br/>数据库索引"]
    
    A --> E["堆<br/>优先队列"]
    A --> F["Trie树<br/>前缀匹配"]
    
    style C fill:#e8f5e9
    style D fill:#fff3e0
    style F fill:#e3f2fd

三、核心算法

3.1 排序算法

算法平均时间空间稳定适用场景
快速排序O(n log n)O(log n)通用首选
归并排序O(n log n)O(n)链表/外部排序
堆排序O(n log n)O(1)内存受限
插入排序O(n²)O(1)小数据/近似有序

3.2 搜索算法

算法时间复杂度前提条件
线性搜索O(n)无要求
二分搜索O(log n)有序数组
哈希搜索O(1)有哈希表

3.3 动态规划入门

核心思想:把大问题拆成小问题,保存子问题结果避免重复计算

经典案例:爬楼梯
dp[i] = dp[i-1] + dp[i-2]
时间:O(n),空间:O(1)(只保留前两个状态)

四、Web开发中的应用

场景使用的数据结构/算法
缓存Key设计哈希表
数据库索引B+树
搜索结果联想Trie树
排行榜堆/有序集合
路由匹配前缀树/Trie
去重哈希集合
会话管理栈(LRU淘汰)

五、本章总结

核心规律:没有最好的数据结构,只有最适合场景的。选择时考虑:访问模式(读多写少 vs 写多读少)、数据规模、一致性要求。

关键记忆点

  • ✅ 数组:随机访问快,插入删除慢
  • ✅ 链表:插入删除快,随机访问慢
  • ✅ 哈希表:查找O(1),但无序
  • ✅ B+树:数据库索引的核心结构
  • ✅ 动态规划:保存子问题结果,避免重复计算

延伸阅读