数据结构:绪论

这是本文档旧的修订版!


绪论:数据结构与算法详解

程序设计的核心公式(N.沃思):

程序 = 数据结构 + 算法
  • 数据结构:就像是做饭的“食材”和“摆盘方式”(问题的数学模型)。
  • 算法:就像是“菜谱”和“烹饪步骤”(处理问题的策略)。

我们通过一个“学生信息管理系统”的例子来理解以下概念:

  • 数据 (Data):计算机处理的符号总称。
  • 数据元素 (Data Element):数据的基本单位
    • *例子*:学生表中的一行记录(包含姓名、学号、班级)。
  • 数据项 (Data Item):构成元素的不可分割的最小单位。
    • *例子*:某条记录中的“学号”这一项。
  • 数据对象 (Data Object):性质相同的数据元素的集合。
    • *例子*:整数集所有学生的集合

逻辑结构描述的是数据在思想上的关联,与它们在电脑里存哪里无关。

类型 关系特点 生活中的例子 图示说明
集合结构 松散。除了“同在一个圈子”外,没别的关系。 操场上散开做操的同学。 ( A B C )
线性结构 一对一。像一条线,有头有尾,前后相连。 排队打饭的队伍;挂在墙上的一串钥匙。 A → B → C
树状结构 一对多。层次分明,像倒过来的树。 电脑里的文件夹(C盘 → 用户 → 文档);家族族谱。 A → (B, C)
图形结构 多对多。错综复杂,四通八达。 城市交通网;微信的好友关系网。 A ↔ B ↔ C

这是逻辑结构在计算机中的物理实现。这是本章的重点,我们可以通过 HTML 可视化来理解。

1. 顺序存储 (Sequential Storage) - 类似数组

特点:物理位置紧邻,像电影院连座。

1101
1105
1202
1203
addr:0 addr:1 addr:2 addr:3
2. 链式存储 (Linked Storage) - 类似寻宝游戏

特点:物理位置随意,靠“小纸条(指针)”指引下一站。

1101
1105
1202
^

3.1 详细对比

特性 顺序存储 (数组) 链式存储 (链表)
物理位置 必须相邻。 可以不相邻,散落在内存各处。
关系表示 靠位置体现($A$ 的后面就是 $B$)。 靠指针体现($A$ 手里拿着 $B$ 的地址)。
优点 查找快(直接算地址),存储密度大。 插入、删除快(不用移动元素,改指针即可)。
缺点 插入删除需要移动大量元素;需要预分配空间。 查找慢(必须从头找);指针占用额外空间。

算法不仅要算出结果,还要算得“快”且“省”。

记忆口诀:有输(出)入,可行确(定)穷

  1. 有穷性:算法不能陷入死循环,必须能跑完。
  2. 确定性:代码不能模棱两可,同样的输入必须得到同样的输出。
  3. 可行性:每一步都能通过有限次基本运算完成。
  4. 输入:0个或多个(例如 `void print_hello()` 就没有输入)。
  5. 输出:1个或多个(没有输出的算法是无意义的)。

我们用 大O记号 ($O$) 来表示“大概的趋势”,而不是精确的秒数。

2.1 时间复杂度 (Time Complexity)

随着数据量 $n$ 的增大,耗时增长的趋势。

* $O(1)$ 常数阶:无论数据多少,耗时不变。

  • *例子*:访问数组的第 5 个元素 `a[5]`。

* $O(n)$ 线性阶:数据翻倍,耗时翻倍。

  • *例子*:遍历一个列表,找某个数。

* $O(n^2)$ 平方阶:数据翻倍,耗时变成 4 倍。

  • *例子*:双层循环,如冒泡排序。

* $O(\log_2 n)$ 对数阶:非常快。

  • *例子*:二分查找(在有序书中找页码)。

效率排序: $O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n)$

这是绪论中最具实战意义的部分,以下结合图片内容进行深度解析。

  • 别名:暴力破解法。
  • 核心“笨”办法,试遍所有可能
  • 案例破解密码
    • 假设密码是4位数字(0000-9999)。
    • 算法:从 0000 开始,一直试到 9999。
    • *分析*:理论上一定能找到,但如果密码很长,时间会无法接受。

* 核心:利用旧值推出新值。 * 案例阶乘计算 ($n!$)

  • 公式:$n! = n \times (n-1)!$
  • 边界:$0! = 1$
  • 实现:使用 `for` 循环(迭代)或者函数调用自身(递归)。
  • *代码逻辑*:`result = 1; for(i=1; i⇐n; i++) { result = result * i; }`
  • 核心大事化小,各个击破
  • 三步走
    • 分 (Divide):把大问题切成几个独立的小问题。
    • 治 (Conquer):递归解决小问题。
    • 合 (Combine):把小问题的结果拼起来。
  • 案例排序问题
    • 要给 1000 个数排序,先分成两组各 500 个,再分…直到只剩 1 个数(不用排了),然后再两两合并有序序列。
  • 关键条件:子问题必须是相互独立的(子问题A的结果不依赖子问题B)。
  • 核心目光短浅,只顾眼前。不追求整体最优,只做当前看起来最好的选择。
  • 特点:一旦选定,不回溯(不后悔)。
  • 案例找零钱问题
    • *场景*:要找回 15 元,现有面值 11元、5元、1元。
    • *贪心策略*:优先选最大的。
      • 选 11元(剩4元)。
      • 5元不够,选 1元(剩3元)。
      • 选 1元…
      • 结果:1张11元 + 4张1元 = 5张
    • *问题*:这真的最优吗?
      • 最优解其实是:3张5元 = 3张
    • *结论*:贪心算法,但不一定能得到全局最优解(除非硬币面值设计得好,如 1, 5, 10)。
  • 核心精打细算,拒绝重复
  • 与分治法的区别
    • 分治法处理独立子问题。
    • 动态规划处理重叠子问题(即:很多小问题是一样的)。
  • 手段:引入一个表格(数组),算过的结果记下来,下次直接查表,不用重算。
  • 案例斐波那契数列 (Fibonacci)
    • 求 `Fib(5)` 需要 `Fib(4)` 和 `Fib(3)`。
    • 求 `Fib(4)` 需要 `Fib(3)` 和 `Fib(2)`。
    • *发现*:`Fib(3)` 被重复计算了!
    • *DP做法*:算完 `Fib(3)` 后存入数组 `arr[3]`。下次需要时,直接读取 `arr[3]`。
  • 适用场景:最优化问题,具有最优子结构重叠子问题性质。

该主题尚不存在

您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。

  • 数据结构/绪论.1765438352.txt.gz
  • 最后更改: 2025/12/11 15:32
  • 张叶安