差别
这里会显示出您选择的修订版和当前版本之间的差别。
| 两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
| 数据结构:绪论 [2025/12/11 15:37] – 张叶安 | 数据结构:绪论 [2025/12/11 16:24] (当前版本) – [1. 穷举法 (Brute Force)] 张叶安 | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| ====== 绪论:数据结构与算法详解 (进阶版) ====== | ====== 绪论:数据结构与算法详解 (进阶版) ====== | ||
| - | 程序设计的核心公式(N.沃思): | + | **"程序设计 = 数据结构 + 算法"** —— 尼克劳斯·沃思 |
| - | > **程序 | + | |
| - | | + | 如果把编程比作**烹饪**: |
| - | * **算法**:是**动态**的。就像图书管理员找书的流程(是从左往右一本本找,还是先查索引再找)。 | + | * **数据结构 |
| + | * | ||
| + | |||
| + | 本教程旨在通过可视化的方式,深入剖析计算机科学的这两大基石。 | ||
| ===== 第一部分:数据结构 (Data Structure) ===== | ===== 第一部分:数据结构 (Data Structure) ===== | ||
| + | |||
| + | 数据结构不仅仅是存储数据,更是为了**高效地**检索和操作数据。 | ||
| ==== 1. 核心概念辨析 ==== | ==== 1. 核心概念辨析 ==== | ||
| - | 我们通过一个**“学生信息管理系统”**的例子来理解: | + | 在深入具体结构前,我们需要厘清以下术语的层级关系: |
| - | * **数据 (Data)**:计算机处理的符号总称。 | + | ^ 术语 ^ 定义 ^ 举例 (学生管理系统) ^ |
| - | | + | | **数据 (Data)** |
| - | | + | | **数据元素 (Data Element)** |
| - | | + | | **数据项 (Data Item)** |
| + | | **数据对象 (Data Object)** | ||
| - | ==== 2. 逻辑结构可视化 | + | ==== 2. 逻辑结构:数据之间的“思想关系” |
| - | 逻辑结构描述的是数据在**思想上**的关联。以下是四种基本结构的交互式演示: | + | 逻辑结构是指数据元素之间的相互关系,它与数据在计算机中的存储位置无关。我们通常将其分为四类。 |
| < | < | ||
| 行 27: | 行 32: | ||
| < | < | ||
| < | < | ||
| + | /* 容器基础样式 */ | ||
| .ds-container { | .ds-container { | ||
| - | font-family: | + | font-family: |
| - | background-color: | + | background-color: |
| - | padding: | + | padding: |
| - | border-radius: | + | border-radius: |
| - | border: 1px solid #ddd; | + | border: 1px solid #e0e0e0; |
| - | | + | |
| + | margin: 0 auto 20px auto; | ||
| } | } | ||
| .ds-grid { | .ds-grid { | ||
| display: grid; | display: grid; | ||
| - | grid-template-columns: | + | grid-template-columns: |
| - | gap: 20px; | + | gap: 25px; |
| } | } | ||
| .ds-card { | .ds-card { | ||
| background: white; | background: white; | ||
| - | padding: | + | padding: |
| - | border-radius: | + | border-radius: |
| - | box-shadow: 0 2px 5px rgba(0, | + | box-shadow: 0 4px 6px rgba(0, |
| text-align: center; | text-align: center; | ||
| - | transition: | + | transition: |
| + | border-bottom: | ||
| + | display: flex; | ||
| + | flex-direction: | ||
| + | align-items: | ||
| } | } | ||
| .ds-card: | .ds-card: | ||
| - | transform: translateY(-5px); | + | transform: translateY(-7px); |
| - | box-shadow: 0 5px 15px rgba(0, | + | box-shadow: 0 10px 20px rgba(0, |
| + | border-bottom-color: | ||
| } | } | ||
| - | .ds-icon { | + | .ds-icon-box { |
| - | height: | + | height: |
| + | width: 100%; | ||
| display: flex; | display: flex; | ||
| align-items: | align-items: | ||
| justify-content: | justify-content: | ||
| - | margin-bottom: | + | margin-bottom: |
| + | background: #fafafa; | ||
| + | border-radius: | ||
| } | } | ||
| - | .ds-node { | + | .ds-svg { |
| - | width: | + | width: |
| - | height: | + | height: |
| - | | + | |
| - | | + | } |
| - | | + | .ds-shape { fill: # |
| - | | + | .ds-shape-2 { fill: #e74c3c; } |
| + | | ||
| + | .ds-shape-4 { fill: #2ecc71; } | ||
| + | .ds-line { stroke: #34495e; stroke-width: | ||
| + | .ds-dashed { stroke: #bdc3c7; stroke-width: | ||
| + | .anim-float-1 { animation: float 3s infinite ease-in-out; | ||
| + | .anim-float-2 { animation: float 4s infinite ease-in-out 0.5s; } | ||
| + | .anim-float-3 { animation: float 3.5s infinite ease-in-out 1.2s; } | ||
| + | .anim-float-4 { animation: float 4.5s infinite ease-in-out 2s; } | ||
| + | @keyframes float { | ||
| + | | ||
| + | 50% { transform: translateY(-4px); } | ||
| } | } | ||
| - | | + | |
| - | .set-anim .ds-node | + | |
| - | @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } } | + | p.example |
| - | + | ||
| - | /* 线性结构 */ | + | |
| - | .linear-box { display: flex; gap: 5px; justify-content: | + | |
| - | | + | |
| - | + | ||
| - | /* 树形结构 */ | + | |
| - | .tree-box { display: flex; flex-direction: | + | |
| - | .tree-row | + | |
| - | + | ||
| - | /* 图形结构 */ | + | |
| - | | + | |
| - | .g-node { position: absolute; } | + | |
| - | | + | |
| - | + | ||
| - | h4 { margin: 10px 0 5px; color: #2c3e50; } | + | |
| - | p.desc { font-size: 0.9em; color: #666; margin: | + | |
| </ | </ | ||
| </ | </ | ||
| 行 91: | 行 101: | ||
| <div class=" | <div class=" | ||
| <div class=" | <div class=" | ||
| - | <!-- 集合 --> | + | < |
| <div class=" | <div class=" | ||
| - | <div class=" | + | <div class=" |
| - | <div class=" | + | <svg class=" |
| - | <div class=" | + | |
| + | | ||
| + | <circle cx="90" | ||
| + | | ||
| + | <circle cx=" | ||
| + | <circle cx="100" | ||
| + | <circle cx=" | ||
| + | | ||
| </ | </ | ||
| < | < | ||
| - | <p class=" | + | <p class=" |
| + | <p class=" | ||
| </ | </ | ||
| - | <!-- 线性 --> | + | < |
| <div class=" | <div class=" | ||
| - | <div class=" | + | <div class=" |
| - | <div class=" | + | <svg class=" |
| - | <div class=" | + | <line x1=" |
| - | <div class=" | + | |
| - | <div class=" | + | <circle cx=" |
| - | </div> | + | |
| + | <circle cx=" | ||
| + | | ||
| + | </svg> | ||
| </ | </ | ||
| < | < | ||
| - | <p class=" | + | <p class=" |
| + | <p class=" | ||
| </ | </ | ||
| - | <!-- 树形 --> | + | < |
| <div class=" | <div class=" | ||
| - | <div class=" | + | <div class=" |
| - | <div class=" | + | <svg class=" |
| - | <div class=" | + | <line x1=" |
| - | <div class=" | + | |
| - | <div class=" | + | <line x1=" |
| - | <div class=" | + | <line x1=" |
| - | </div> | + | |
| - | </div> | + | <line x1=" |
| + | | ||
| + | <circle cx=" | ||
| + | <circle cx=" | ||
| + | <circle cx=" | ||
| + | <circle cx=" | ||
| + | <circle cx=" | ||
| + | <circle cx=" | ||
| + | </svg> | ||
| </ | </ | ||
| < | < | ||
| - | <p class=" | + | <p class=" |
| + | <p class=" | ||
| </ | </ | ||
| - | <!-- 图形 --> | + | < |
| <div class=" | <div class=" | ||
| - | <div class=" | + | <div class=" |
| - | <div class=" | + | <svg class=" |
| - | <div class=" | + | <line x1=" |
| - | <div class=" | + | <line x1="70" |
| - | <div class=" | + | |
| - | <!-- 简单的连线模拟 | + | <line x1=" |
| - | <div style="position: | + | <line x1="40" |
| - | <div style="position: | + | |
| - | <div style="position: | + | <line x1=" |
| - | </div> | + | <line x1="20" |
| + | | ||
| + | <circle cx=" | ||
| + | <circle cx="120" cy=" | ||
| + | <circle cx="40" cy=" | ||
| + | <circle cx="100" cy=" | ||
| + | </svg> | ||
| </ | </ | ||
| < | < | ||
| - | <p class=" | + | <p class=" |
| + | <p class=" | ||
| </ | </ | ||
| </ | </ | ||
| </ | </ | ||
| </ | </ | ||
| - | </ | ||
| </ | </ | ||
| - | ==== 3. 存储结构:数据在“内存”中的样子 ==== | + | === 2.1 集合 (Set) === |
| + | * | ||
| + | * | ||
| - | 这是逻辑结构的物理实现。 | + | === 2.2 线性结构 |
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * **栈 (Stack)**:后进先出 (LIFO),如弹夹。 | ||
| + | * | ||
| - | === 3.1 顺序存储 vs 链式存储 | + | === 2.3 树状结构 (Tree) |
| + | * | ||
| + | * | ||
| - | ^ 特性 ^ 顺序存储 (数组) ^ 链式存储 | + | === 2.4 图形结构 |
| - | | **物理位置** | 必须相邻 | 可以散落在内存各处 | | + | * |
| - | | **优点** | **查找快** (直接算地址),存储密度大 | **增删快** (改指针即可),不需预分配 | | + | * |
| - | | **缺点** | 插入删除需移动元素 | 查找慢 (必须从头找),指针占空间 | | + | |
| - | === 3.2 进阶存储方式 | + | ==== 3. 存储结构:数据在“内存”中的物理形态 ==== |
| - | * **索引存储**:建立一张“目录表”。先查目录找到地址,再找内容。(类似字典的拼音索引)。 | + | 逻辑结构是“想出来的”,存储结构是“写在内存条上的”。 |
| - | * **散列存储 (Hash)**:**速度之王**。 | + | |
| - | * // | + | === 3.1 顺序存储 (Sequential Storage) === |
| - | * //例子//:存 `105`,公式 `key % 10`,直接扔进 `5` 号房间。查找时直接去 `5` 号拿。 | + | * **原理**:把逻辑上相邻的元素存储在**物理位置也相邻**的存储单元中。 |
| + | * **代表**:数组 (Array)。 | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | |||
| + | === 3.2 链式存储 (Linked Storage) === | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | |||
| + | === 3.3 索引存储与散列存储 === | ||
| + | * | ||
| + | * | ||
| + | * 不通过比较,而是通过公式(哈希函数)直接计算出存储地址。 | ||
| + | * **冲突 (Collision)**:当不同的数据算出了相同的地址时,需要特殊处理(如拉链法)。 | ||
| ===== 第二部分:算法 (Algorithm) ===== | ===== 第二部分:算法 (Algorithm) ===== | ||
| - | ==== 1. 算法效率度量 | + | 算法是解决特定问题求解步骤的描述。一个好的算法应该具备:**正确性、可读性、健壮性、高效率**。 |
| + | |||
| + | ==== 1. 算法效率度量:大O记号 | ||
| - | 我们用 **大O记号** 表示随着数据量 $n$ 增大,耗时增长的趋势。 | + | 我们不计算具体的秒数(因为这取决于机器性能),而是计算**操作步骤数量随数据量 $n$ 的增长趋势**。 |
| < | < | ||
| 行 218: | 行 289: | ||
| transition: width 1s ease-out; | transition: width 1s ease-out; | ||
| } | } | ||
| - | /* 颜色定义 */ | ||
| .bg-green { background-color: | .bg-green { background-color: | ||
| .bg-blue { background-color: | .bg-blue { background-color: | ||
| 行 248: | 行 318: | ||
| </ | </ | ||
| </ | </ | ||
| - | </ | ||
| </ | </ | ||
| - | | + | === 1.1 常见复杂度详解 === |
| - | * **$O(n)$ 线性阶**:数据翻倍,耗时翻倍。 | + | |
| - | * **$O(n^2)$ 平方阶**:数据翻倍,耗时变 4 倍(双层循环)。 | + | |
| - | * **$O(\log_2 n)$ 对数阶**:非常快(二分查找)。 | + | <code c> |
| + | int n = 10000; | ||
| + | x = n + 1; // 无论n多大,这行只执行一次 | ||
| + | </ | ||
| + | * | ||
| + | <code c> | ||
| + | for(int i=0; i<n; i++) { ... } | ||
| + | </ | ||
| + | * | ||
| + | <code c> | ||
| + | for(int i=0; i<n; i++) { | ||
| + | for(int j=0; j<n; j++) { ... } | ||
| + | } | ||
| + | </ | ||
| + | * | ||
| + | <code c> | ||
| + | while(n > 1) { | ||
| + | n = n / 2; // 1024 -> 512 -> 256 ... 10次就到了 | ||
| + | } | ||
| + | </ | ||
| ===== 第三部分:五大常用算法思想详解 ===== | ===== 第三部分:五大常用算法思想详解 ===== | ||
| + | |||
| + | 这是算法的灵魂,掌握这些思想比背诵代码更重要。 | ||
| ==== 1. 穷举法 (Brute Force) ==== | ==== 1. 穷举法 (Brute Force) ==== | ||
| - | * **核心**:暴力破解,试遍所有可能。 | + | |
| - | * **优化**:**剪枝 (Pruning)**。如果在搜索过程中发现当前路径不可能成功,就直接放弃,不再往下试(剪掉树枝)。 | + | * **别名**:暴力破解法。 |
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | |||
| + | ==== 2. 分治法 (Divide and Conquer) ==== | ||
| + | |||
| + | * | ||
| + | * | ||
| + | * | ||
| + | |||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | .dc-wrapper { | ||
| + | text-align: center; | ||
| + | padding: 15px; | ||
| + | background: #f0f4c3; | ||
| + | border-radius: | ||
| + | border: 1px solid #dce775; | ||
| + | } | ||
| + | .dc-block { | ||
| + | display: inline-block; | ||
| + | background: #8bc34a; | ||
| + | color: white; | ||
| + | padding: 8px 15px; | ||
| + | border-radius: | ||
| + | margin: 5px; | ||
| + | font-size: 12px; | ||
| + | box-shadow: 0 2px 4px rgba(0, | ||
| + | } | ||
| + | .dc-arrow { color: #555; font-size: 12px; margin: 5px 0; } | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | < | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | </ | ||
| + | <div class=" | ||
| + | < | ||
| + | <div class=" | ||
| + | <span style=" | ||
| + | <div class=" | ||
| + | </ | ||
| + | <div class=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ==== 3. 动态规划 (Dynamic Programming, | ||
| + | |||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * 求 $F(4)$ 时需要算 $F(3) + F(2)$。 | ||
| + | * | ||
| + | * | ||
| + | |||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | .dp-container { | ||
| + | display: flex; | ||
| + | gap: 20px; | ||
| + | justify-content: | ||
| + | background: #e3f2fd; | ||
| + | padding: 20px; | ||
| + | border-radius: | ||
| + | border: 1px solid #bbdefb; | ||
| + | } | ||
| + | .dp-box { | ||
| + | flex: 1; | ||
| + | background: white; | ||
| + | padding: 10px; | ||
| + | border-radius: | ||
| + | text-align: center; | ||
| + | } | ||
| + | .dp-title { font-weight: | ||
| + | .dp-table { | ||
| + | display: grid; | ||
| + | grid-template-columns: | ||
| + | gap: 2px; | ||
| + | background: #ccc; | ||
| + | padding: 2px; | ||
| + | margin-top: 10px; | ||
| + | } | ||
| + | .dp-cell { background: #fff; padding: 5px; font-size: 10px; } | ||
| + | .dp-cell.filled { background: #4caf50; color: white; } | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <span class=" | ||
| + | <div style=" | ||
| + | f(5) 需要算 f(4) 和 f(3)< | ||
| + | f(4) 需要算 f(3) 和 f(2)< | ||
| + | <span style=" | ||
| + | </ | ||
| + | </ | ||
| + | <div class=" | ||
| + | <span class=" | ||
| + | <div style=" | ||
| + | 算过 f(3) 吗?< | ||
| + | 算过 -> <span style=" | ||
| + | 没算 -> 算出并填表 | ||
| + | </ | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ==== 4. 贪心算法 (Greedy) ==== | ||
| + | |||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * | ||
| + | * 66 < 100,跳过。 | ||
| + | * 66 >= 50,**给一张 50**。剩 16。 | ||
| + | * 16 < 20,跳过。 | ||
| + | * 16 >= 10,**给一张 10**。剩 6。 | ||
| + | * 6 >= 5,**给一张 5**。剩 1。 | ||
| + | * **给一张 1**。结束。 | ||
| + | * | ||
| + | |||
| + | ==== 5. 回溯法 (Backtracking) ==== | ||
| + | |||
| + | * | ||
| + | * | ||
| + | * **剪枝 (Pruning)**:在搜索过程中,如果发现当前分支已经不可能找到解,就直接切断该分支,不再往下搜,大大提高效率。 | ||
| + | * | ||
| + | |||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | .bt-maze { | ||
| + | position: relative; | ||
| + | width: 200px; | ||
| + | height: 120px; | ||
| + | background: #333; | ||
| + | margin: 0 auto; | ||
| + | border-radius: | ||
| + | overflow: hidden; | ||
| + | } | ||
| + | .bt-path { | ||
| + | position: absolute; | ||
| + | background: #fff; | ||
| + | transition: all 0.5s; | ||
| + | } | ||
| + | .p1 { top: 50px; left: 10px; width: 40px; height: 10px; } | ||
| + | .p2 { top: 20px; left: 40px; width: 10px; height: 40px; } | ||
| + | .p3 { top: 20px; left: 40px; width: 40px; height: 10px; background: #f44336; } | ||
| + | .p4 { top: 50px; left: 40px; width: 60px; height: 10px; } | ||
| + | .p5 { top: 50px; left: 90px; width: 10px; height: 40px; } | ||
| + | .p6 { top: 80px; left: 90px; width: 60px; height: 10px; background: #4caf50; } | ||
| + | .bt-label { | ||
| + | position: absolute; | ||
| + | color: white; | ||
| + | font-size: 10px; | ||
| + | padding: 2px; | ||
| + | } | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <div style=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | </ | ||
| + | <p style=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ===== 总结:如何选择算法? ===== | ||
| + | |||
| + | | 场景特点 | 推荐策略 | 核心思想 | | ||
| + | | 问题可拆分,子问题独立 | **分治法** | 大事化小 | | ||
| + | | 问题可拆分,子问题重叠 | **动态规划** | 拒绝健忘,查表 | | ||
| + | | 需要快速找到一个可行解 | **贪心算法** | 目光短浅,先拿再说 | | ||
| + | | 需要遍历所有解或路径 | **回溯法** | 不撞南墙不回头 | | ||
| + | | 没有任何规律 | **穷举法** | 暴力出奇迹 | | ||