从现实问题到数据结构

数据结构不是凭空发明的一堆容器名字。它是对现实问题的分析、抽象的产物:先有现实中的事物和关系,抽出共同结构,才落成数据结构。而且数据结构不止一种——领域数据(业务对象)、通用结构(Core)、平台数据(Infrastructure)是三类完全不同的东西,各有各的来源和用途。


一、数据结构从哪里来

教材常按容器讲:数组、链表、栈、队列、树、图、哈希表……好像它们是独立存在的知识。

但它们其实是从现实问题里长出来的。每个数据结构背后都有一个现实场景在逼它出现:

1
2
3
4
5
6
7
现实问题                    抽象出来            数据结构
──────────────────────────────────────────────────────
一排人按顺序排队,先来的先服务 先进先出 队列
一叠盘子,后放的先拿走 后进先出 栈
点名册按学号排好,快速找某个人 编号 + 查找 数组 / 哈希表
家族谱:父 → 子 → 孙 层级归属 树
城市间的路,任意两点可连通 多对多连接 图

关键一步是抽象:把现实问题里的具体人、盘子、学号抹掉,只留下「顺序」「先来后到」「层级」「连通」这些结构关系。

数据结构 = 对现实问题分析抽象后得到的结构关系。


二、领域数据:业务对象是数据结构的第一类

数据结构真正落到程序里,第一类不是数组链表,而是领域数据(Domain)——它描述业务对象。

比如调试器里的领域对象:

1
2
3
4
5
6
7
Process       进程
Module 模块
Thread 线程
MemoryRegion 内存区域
Instruction 指令
Breakpoint 断点
Symbol 符号

比如:

1
2
3
4
5
struct ProcessInfo {
uint32_t pid;
std::string name;
uint64_t base_addr;
};

这个 ProcessInfo 是对现实中「进程」的分析抽象:进程有什么属性(pid、名字、基址)?谁需要它(进程列表功能)?它和别的对象什么关系(一个进程有多个线程)?

领域数据 = 从现实业务问题分析抽象出来的对象。 它是数据结构的「领域层」。


三、通用结构:Core——与业务无关的容器

第二类是通用数据结构(Core),与业务无关:

1
2
3
Vector       List        Queue        Stack
HashMap Tree Graph BitSet
RingBuffer ObjectPool
1
2
template<class T>
class RingBuffer { ... };

它可以在网络、日志、音频、游戏、调试器里用——没有任何业务含义

这两类的来源完全不同:

1
2
Domain 数据 ← 从「这个业务领域」分析抽象(调试器→进程/断点)
Core 数据 ← 从「通用的结构关系」分析抽象(排队→队列,层级→树)

Domain 回答「这个世界有什么对象」,Core 回答「这些对象用什么容器组织」。


四、基础设施数据:Infrastructure——平台资源也是数据结构

第三类常被忽略——平台数据(Infrastructure)

1
2
3
SocketHandle     sockaddr_in     OVERLAPPED
DriverContext ThreadContext PEHeader
IMAGE_NT_HEADERS
1
2
3
4
struct SocketContext {
SOCKET socket;
sockaddr_in addr;
};

这不是业务对象(不是领域数据),也不是通用容器(不是 Core),它描述的是平台资源:操作系统/驱动/文件格式给程序的东西。


五、三类数据一览

1
2
3
4
Data
├── Domain 业务对象:ProcessInfo / Breakpoint / ModuleInfo
├── Core 通用结构:Vector / HashMap / RingBuffer / Graph
└── Infrastructure 平台数据:SocketContext / PEHeader / ThreadContext

放错层的典型症状:

1
2
3
4
5
6
7
8
❌ 把 Platform 结构丢进 Domain
→ 业务层突然依赖 OS 细节,换平台就崩

❌ 把业务对象塞进 Core 容器层
→ 容器层开始出现「进程」「断点」这种词,通用性被破坏

✅ 每一层的数据只承担一种职责
→ Domain 管业务对象,Core 管结构,Infrastructure 管平台

六、数据结构、算法、接口是同一个抽象过程的三面

「功能 = 算法 + 数据结构 + 接口」里的三者,其实来自同一个分析抽象过程:

1
2
3
4
5
6
7
8
9
现实问题
↓ 分析
领域对象(谁、有什么属性、和谁有关系)
↓ 抽象
数据结构(对象怎么表示、用什么容器)

算法(对数据做什么操作)

接口(别人怎么调用)

而且数据、算法、接口三类各自都有同样的分层

类型 Domain Core Infrastructure
数据 ProcessInfo、Breakpoint Vector、HashMap SocketContext、PEHeader
算法 内存扫描、断点管理 排序、搜索、图算法 PE 解析、协议解析
接口 IProcessService IContainer IProcess、INetwork

Domain 并不是「所有数据结构的目录」,而是「业务数据结构的目录」——这一点和领域模型、领域对象分析两条线直接相关。


七、和其他线的关系

1
2
3
4
5
6
7
8
9
10
11
数据结构 ←→ 领域模型(本系列另一条线)
领域模型分析「业务世界有什么对象、什么关系」
数据结构落地「这些对象在程序里怎么表示、用什么容器」

数据结构 ←→ 算法类型与描述形式
算法 = 对数据的操作;数据结构 = 被操作的对象
数据的类型决定算法怎么描述(容器→遍历,图→图算法)

数据结构 ←→ 模块三要素(主线)
主线讲「模块 = 数据 + 算法 + 接口」
本线讲「模块里的数据从哪来、分几类」

收束

1
2
3
4
5
6
7
8
9
10
数据结构不是容器清单,是从现实问题分析抽象出来的
现实问题 → 抽象出结构关系 → 数据结构

数据结构分三类,来源不同:
Domain 从业务领域分析(进程/断点/订单)
Core 从通用结构抽象(队列/树/图)
Infrastructure 从平台资源而来(socket/PE 头)

放错层的代价:业务层依赖平台细节 / 容器层混入业务
数据、算法、接口是同一次抽象的三面,各有 Domain/Core/Infrastructure 分层

先有现实问题的分析,才有数据结构。 理解「数据从哪来、属于哪一层」,比背下所有容器名字更重要。