绪论:数据结构与算法详解 (进阶版)
“程序设计 = 数据结构 + 算法” —— 尼克劳斯·沃思 (Niklaus Wirth, 图灵奖得主)
如果把编程比作烹饪:
本教程旨在通过可视化的方式,深入剖析计算机科学的这两大基石。
第一部分:数据结构 (Data Structure)
数据结构不仅仅是存储数据,更是为了高效地检索和操作数据。
1. 核心概念辨析
在深入具体结构前,我们需要厘清以下术语的层级关系:
| 术语 | 定义 | 举例 (学生管理系统) |
| 数据 (Data) | 描述客观事物的符号,是计算机操作的对象 | 整个数据库文件 |
| 数据元素 (Data Element) | 数据的基本单位,在程序中通常作为一个整体处理 | 一名学生的完整记录 (行) |
| 数据项 (Data Item) | 构成数据元素的最小单位,不可分割 | 学生的学号、姓名、性别 (列) |
| 数据对象 (Data Object) | 性质相同的数据元素的集合 | 所有学生的集合 (表) |
2. 逻辑结构:数据之间的“思想关系”
逻辑结构是指数据元素之间的相互关系,它与数据在计算机中的存储位置无关。我们通常将其分为四类。
集合结构 (Set)
元素同属一个范围,但无序、无关联。
例:购物车里的商品
线性结构 (Linear)
元素首尾相接,严格的一对一顺序。
例:排队、链表、数组
树状结构 (Tree)
一对多的层级关系,严谨的分支体系。
例:公司组织架构、文件系统
图形结构 (Graph)
多对多的网状关系,任意节点皆可相连。
例:互联网、神经网络、交通图
2.1 集合 (Set)
2.2 线性结构 (Linear)
2.3 树状结构 (Tree)
2.4 图形结构 (Graph)
3. 存储结构:数据在“内存”中的物理形态
逻辑结构是“想出来的”,存储结构是“写在内存条上的”。
3.1 顺序存储 (Sequential Storage)
3.2 链式存储 (Linked Storage)
3.3 索引存储与散列存储
第二部分:算法 (Algorithm)
算法是解决特定问题求解步骤的描述。一个好的算法应该具备:正确性、可读性、健壮性、高效率。
1. 算法效率度量:大O记号
我们不计算具体的秒数(因为这取决于机器性能),而是计算操作步骤数量随数据量 $n$ 的增长趋势。
1.1 常见复杂度详解
int n = 10000;
x = n + 1; // 无论n多大,这行只执行一次
for(int i=0; i<n; i++) { ... }
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) { ... }
}
while(n > 1) {
n = n / 2; // 1024 -> 512 -> 256 ... 10次就到了
}
第三部分:五大常用算法思想详解
1. 穷举法 (Brute Force)
2. 分治法 (Divide and Conquer)
大问题 (排序 8 个数)
↓ 拆分 (Divide)
↓ 递归解决 (Conquer)
↑ 合并结果 (Merge)
3. 动态规划 (Dynamic Programming, DP)
核心:历史记录。通过空间换时间。
原理:将复杂问题分解为子问题,但与分治法不同的是,DP 的子问题是重叠的。为了避免重复计算,DP 会把每个子问题的结果存进一张表里。
案例:斐波那契数列 (1, 1, 2, 3, 5, 8…)
求第 5 个数:$F(5) = F(4) + F(3)$
求 $F(4)$ 时需要算 $F(3) + F(2)$。
注意:$F(3)$ 被计算了两次!如果是递归,$n$ 很大时重复计算量是指数级的。
DP做法:算完 $F(3)$ 就把它记在本子上,下次直接看本子。
普通递归 (傻算)
f(5) 需要算 f(4) 和 f(3)
f(4) 需要算 f(3) 和 f(2)
f(3) 被重复计算了!
动态规划 (记账)
算过 f(3) 吗?
算过 -> 直接查表
没算 -> 算出并填表
4. 贪心算法 (Greedy)
核心:活在当下。
策略:每一步都做出在当前看来最好的选择。它不从整体最优考虑,但在很多情况下(如最小生成树),局部最优能导致全局最优。
案例:找零钱
问题:找 66 元,纸币规格有 100, 50, 20, 10, 5, 1。
贪心策略:优先用面值最大的。
步骤:
66 < 100,跳过。
66 >= 50,给一张 50。剩 16。
16 < 20,跳过。
16 >= 10,给一张 10。剩 6。
6 >= 5,给一张 5。剩 1。
给一张 1。结束。
局限:如果纸币规格是 1, 3, 4,找 6 元。贪心会给 4+1+1 (3张),但最优解是 3+3 (2张)。此时贪心失效,需用 DP。
5. 回溯法 (Backtracking)
先试上方(红),走不通 -> 回溯 -> 改走右方(绿)
总结:如何选择算法?
| 场景特点 | 推荐策略 | 核心思想 |
| 问题可拆分,子问题独立 | 分治法 | 大事化小 |
| 问题可拆分,子问题重叠 | 动态规划 | 拒绝健忘,查表 |
| 需要快速找到一个可行解 | 贪心算法 | 目光短浅,先拿再说 |
| 需要遍历所有解或路径 | 回溯法 | 不撞南墙不回头 |
| 没有任何规律 | 穷举法 | 暴力出奇迹 |