← 返回 Day 29 正文

Day 29 · 图解

Day 029 — 算法入门:图解

时间复杂度对比、排序算法过程、搜索算法过程的图解


1️⃣ 时间复杂度增长趋势

操作数
  ↑
  │   O(n!)                ★
  │                     ★
  │   O(2ⁿ)          ★
  │                ★
  │   O(n²)      ★
  │            ★
  │   O(n log n)  ★
  │          ★
  │   O(n)   ★
  │       ★
  │   O(log n) ★
  │   _★_____
  │  ★ 
  │ ★
  │★_________________________→ 输入规模 n

  ★ — 操作数随着 n 增长

2️⃣ 常见复杂度对比表 (n=1000)

算法         复杂度        操作数(≈)
────────────────────────────────────
常数时间     O(1)          1
哈希查找     O(1)          1
二分查找     O(log n)      10
线性查找     O(n)          1,000
归并排序     O(n log n)    9,966
选择排序     O(n²)         1,000,000
指数时间     O(2ⁿ)         1.07×10³⁰¹
  1000万 ┤      ┌───
        ┤     ██
  100万 ┤    ██          选择/冒泡 O(n²)
        ┤   ██
  10万  ┤  ██
        ┤ ██
  1万   ┤██
        ┤█
  1000  ┤█─────── 归并/快速 O(n log n)
        █
  100   ┤█───── 二分 O(log n)
  10    ┤█───
  1     ┤█─
        └────────────────────
           10   100  1000

  结论: 数据规模越大,好的算法优势越明显!

3️⃣ 冒泡排序过程

原始: [5, 3, 8, 6, 4]

第1趟:
  5 vs 3 → 交换 [3, 5, 8, 6, 4]
  5 vs 8 → 不动 [3, 5, 8, 6, 4]
  8 vs 6 → 交换 [3, 5, 6, 8, 4]
  8 vs 4 → 交换 [3, 5, 6, 4, 8]   ← 8 冒泡到位

第2趟:
  3 vs 5 → 不动 [3, 5, 6, 4, 8]
  5 vs 6 → 不动 [3, 5, 6, 4, 8]
  6 vs 4 → 交换 [3, 5, 4, 6, 8]   ← 6 冒泡到位

第3趟:
  3 vs 5 → 不动 [3, 5, 4, 6, 8]
  5 vs 4 → 交换 [3, 4, 5, 6, 8]   ← 5 冒泡到位

第4趟:
  3 vs 4 → 不动 [3, 4, 5, 6, 8]   ← 全部有序

4️⃣ 选择排序过程

原始: [5 | 3, 8, 6, 4]
       ↑已排序   ↑未排序区

第1趟: 找未排序最小值 3
       [3 | 5, 8, 6, 4]   ← 3 与 5 交换

第2趟: 找未排序最小值 4
       [3, 4 | 8, 6, 5]   ← 4 与 5 交换

第3趟: 找未排序最小值 5
       [3, 4, 5 | 6, 8]   ← 5 与 8 交换

第4趟: 找未排序最小值 6
       [3, 4, 5, 6 | 8]   ← 不动

5️⃣ 插入排序过程

初始:  [5 | 3, 8, 6, 4]
       ↑已排序 ↑未排序

第1步: 拿出 3, 与 5 比较
       [5, 5, 8, 6, 4]   → 5 > 3, 右移
       [3, 5, 8, 6, 4]   → 插入 3

第2步: 拿出 8, 与 5 比较
       [3, 5, 8, 6, 4]   → 8 > 5, 不动

第3步: 拿出 6, 与 8 比较
       [3, 5, 8, 8, 4]   → 8 > 6, 右移
       [3, 5, 6, 8, 4]   → 插入 6

第4步: 拿出 4, 与 8 比较
       [3, 5, 6, 8, 8]   → 8 > 4, 右移
       [3, 5, 6, 6, 8]   → 6 > 4, 右移
       [3, 5, 5, 6, 8]   → 5 > 4, 右移
       [3, 4, 5, 6, 8]   → 插入 4

6️⃣ 快速排序过程

递归树:
                      [3,7,8,5,2,1,9,5,4]
                            │ pivot=5
                    ┌───────┴───────┐
                    │               │
               [3,2,1,4]       [7,8,9,5]
                    │               │
              pivot=2           pivot=8
              ┌───┴───┐       ┌───┴───┐
              │       │       │       │
           [1]    [3,4]    [7,5]    [9]
                     │       │
                pivot=3  pivot=5
                ┌───┐    ┌───┐
                │   │    │   │
               []  [4]  [5]  [7]

合并:
  [1,2,3,4]      [5,7,8,9]
         \           /
      [1,2,3,4,5,5,7,8,9]   ← 注意两个 5

7️⃣ 归并排序过程

         [38, 27, 43, 3, 9, 82, 10]
                /           \
        [38, 27, 43, 3]    [9, 82, 10]
          /       \          /      \
      [38, 27]  [43, 3]  [9, 82]   [10]
       /   \     /   \    /   \      |
    [38]  [27] [43] [3] [9]  [82]  [10]
       \   /     \   /    \   /      |
      [27,38]   [3,43]   [9,82]    [10]
          \       /          \      /
         [3, 27, 38, 43]    [9, 10, 82]
                \               /
            [3, 9, 10, 27, 38, 43, 82]

合并两个有序数组

合并 [27, 38] 和 [3, 43]:

  队列一: [27, 38]      队列二: [3, 43]
     │                       │
     └─────── 27 vs 3 ──────┘
             3 < 27 → 取 3 ✅

  队列一: [27, 38]      队列二: [43]
     │                       │
     └─────── 27 vs 43 ─────┘
             27 < 43 → 取 27 ✅

  队列一: [38]           队列二: [43]
     │                       │
     └─────── 38 vs 43 ─────┘
             38 < 43 → 取 38 ✅

  队列一: []              队列二: [43]
      → 直接追加剩余 43 ✅

  结果: [3, 27, 38, 43]

8️⃣ 二分搜索过程

数组: [1, 3, 4, 6, 7, 8, 9, 12]
目标: 9

第一步:
  [1, 3, 4, 6, 7, 8, 9, 12]
   L=0      mid=3       R=7
   arr[3]=6 < 9 → 搜索右半部分

第二步:
  [7, 8, 9, 12]
   L=4   mid=5   R=7
   arr[5]=8 < 9 → 搜索右半部分

第三步:
  [9, 12]
   L=6  mid=6  R=7
   arr[6]=9 == 9 ✅ 找到!

9️⃣ 各算法对比

        稳定  原地  时间(平均)  时间(最坏)  空间
        ────────────────────────────────────────
冒泡     ✅    ✅     O(n²)     O(n²)       O(1)
选择     ❌    ✅     O(n²)     O(n²)       O(1)
插入     ✅    ✅     O(n²)     O(n²)       O(1)
快速     ❌    ✅     O(n log n) O(n²)      O(log n)
归并     ✅    ❌     O(n log n) O(n log n)  O(n)
Timsort  ✅    ✅     O(n log n) O(n log n)  O(n)  ← Python 内置

🔟 搜索算法对比

数据规模      线性搜索          二分搜索
──────────────────────────────────────
n=100        ~100 次比较       ~7 次比较
n=1,000      ~1,000 次比较     ~10 次比较
n=10,000     ~10,000 次比较    ~14 次比较
n=100,000    ~100,000 次比较   ~17 次比较
n=1,000,000  ~1M 次比较        ~20 次比较

结论: 数据越大,二分搜索优势越明显!