diff --git a/408/数据结构/assets/1.4.dot b/408/数据结构/assets/1.4.dot
new file mode 100644
index 0000000..7ac2a99
--- /dev/null
+++ b/408/数据结构/assets/1.4.dot
@@ -0,0 +1,49 @@
+graph 4 {
+ splines="FALSE";
+
+ /* Entities */
+ 1 [shape = circle]
+ 2 [shape = circle]
+ 3 [shape = circle]
+ 4 [shape = circle]
+ 5 [shape = circle]
+ 6 [shape = circle]
+ 7 [shape = circle]
+ 8 [shape = circle]
+ 9 [shape = circle]
+ 10 [shape = circle]
+ 11 [shape = circle]
+ 12 [shape = circle]
+ 13 [shape = circle]
+ 14 [shape = circle]
+ 15 [shape = circle]
+
+ /* Relationships */
+ 1 -- 2 [style = invis]
+ 1 -- 3
+ 2 -- 4 [style = invis]
+ 2 -- 5 [style = invis]
+ 3 -- 6 [style = invis]
+ 3 -- 7
+ 4 -- 8 [style = invis]
+ 4 -- 9 [style = invis]
+ 5 -- 10 [style = invis]
+ 5 -- 11 [style = invis]
+ 6 -- 12 [style = invis]
+ 6 -- 13 [style = invis]
+ 7 -- 14 [style = invis]
+ 7 -- 15
+
+ /* Ranks */
+ 2 [style = invis]
+ 4 [style = invis]
+ 5 [style = invis]
+ 6 [style = invis]
+ 8 [style = invis]
+ 9 [style = invis]
+ 10 [style = invis]
+ 11 [style = invis]
+ 12 [style = invis]
+ 13 [style = invis]
+ 14 [style = invis]
+}
\ No newline at end of file
diff --git a/408/数据结构/assets/1.4.png b/408/数据结构/assets/1.4.png
new file mode 100644
index 0000000..14c7d7c
Binary files /dev/null and b/408/数据结构/assets/1.4.png differ
diff --git a/408/数据结构/assets/1.5.dot b/408/数据结构/assets/1.5.dot
new file mode 100644
index 0000000..5afdc88
--- /dev/null
+++ b/408/数据结构/assets/1.5.dot
@@ -0,0 +1,46 @@
+graph 5 {
+ splines="FALSE";
+
+ /* Entities */
+ a [shape = circle]
+ b [shape = circle]
+ c [shape = circle]
+ d [shape = circle]
+ e [shape = circle]
+ f [shape = circle]
+ g [shape = circle]
+ 1 [shape = circle]
+ 2 [shape = circle]
+ 3 [shape = circle]
+ 4 [shape = circle]
+ 5 [shape = circle]
+ 6 [shape = circle]
+ 7 [shape = circle]
+ 8 [shape = circle]
+
+ /* Relationships */
+ a -- b
+ a -- c
+ b -- 1 [style = invis]
+ b -- d
+ 1 -- 2 [style = invis]
+ 1 -- 3 [style = invis]
+ d -- 4 [style = invis]
+ d -- 5 [style = invis]
+ c -- e
+ c -- f
+ e -- 6 [style = invis]
+ e -- g
+ f -- 7 [style = invis]
+ f -- 8 [style = invis]
+
+ /* Ranks */
+ 1 [style = invis]
+ 2 [style = invis]
+ 3 [style = invis]
+ 4 [style = invis]
+ 5 [style = invis]
+ 6 [style = invis]
+ 7 [style = invis]
+ 8 [style = invis]
+}
\ No newline at end of file
diff --git a/408/数据结构/assets/1.5.png b/408/数据结构/assets/1.5.png
new file mode 100644
index 0000000..311656c
Binary files /dev/null and b/408/数据结构/assets/1.5.png differ
diff --git a/408/数据结构/assets/1.6.1.png b/408/数据结构/assets/1.6.1.png
new file mode 100644
index 0000000..4adf29e
Binary files /dev/null and b/408/数据结构/assets/1.6.1.png differ
diff --git a/408/数据结构/assets/1.6.png b/408/数据结构/assets/1.6.png
new file mode 100644
index 0000000..68751fa
Binary files /dev/null and b/408/数据结构/assets/1.6.png differ
diff --git a/408/数据结构/assets/1.7.png b/408/数据结构/assets/1.7.png
new file mode 100644
index 0000000..91ff144
Binary files /dev/null and b/408/数据结构/assets/1.7.png differ
diff --git a/408/数据结构/assets/2.2.3.png b/408/数据结构/assets/2.2.3.png
new file mode 100644
index 0000000..aca6939
Binary files /dev/null and b/408/数据结构/assets/2.2.3.png differ
diff --git a/408/数据结构/数据结构期中考试题.md b/408/数据结构/数据结构期中考试题.md
new file mode 100644
index 0000000..a54339f
--- /dev/null
+++ b/408/数据结构/数据结构期中考试题.md
@@ -0,0 +1,292 @@
+# 数据结构期中考试题
+
+## 单项选择题
+
+### 1. 【单选】(5 分)下列程序段的时间复杂度是( )
+
+```cpp
+x = 91;
+y = 1;
+while (y < n) {
+ if (x > 100) {
+ x = x - 10;
+ y = 2 * y;
+ } else {
+ x++;
+ }
+}
+```
+
+- [ ] A. $O(1)$
+- [x] B. $O(\log_2 n)$
+- [ ] C. $O(n^{\frac{1}{2}})$
+- [ ] D. $O(n)$
+
+> 参考答案:B
+>
+> 本题要求具备一定的代码阅读能力。`x` 的初值为 91,每执行 10 次 `x++`,就执行一次 `y = 2 * y`,且 `x` 恢复为初值 91。也就是说,每 11 次循环,会导致 `y = 2 * y`。当 $y \ge n$ 时停止 `while` 循环,因此时间复杂度为 $O(11 \log_2 n) = O(log_2 n)$。
+
+### 2. 【单选】(5 分)使⽤栈 `S` 进⾏括号匹配,括号序列为 `{{}([()]()[])}`,则栈 `S` 的容量⾄少是( )
+
+- [ ] A. 2
+- [ ] B. 3
+- [x] C. 4
+- [ ] D. 5
+
+> 参考答案:C
+>
+> 括号匹配的过程中,扫描到左括号,则入栈,扫描到右括号,则弹出栈顶左括号,并与右括号进行匹配。栈 `S` 的变化如下:
+>
+> ① `{` 入栈,② `{` 入栈,③ `{` 出栈,④ `(` 入栈,⑤ `[` 入栈,⑥ `(` 入栈,⑦ `(` 出栈,⑧ `[` 出栈,⑨ `(` 入栈,⑩ `(` 出栈,⑪ `[` 入栈,⑫ `[` 出栈, ⑬ `(` 出栈,⑭ `{` 出栈
+>
+> 当运行到第 ⑥ 步时,栈内元素最多,共 4 个,因此栈的大小至少为 4
+
+### 3. 【单选】(5 分)有一个 10 阶的三对角矩阵 $M$,其元素 $M_{i, j} (1 \le i, j \le 10)$ 按列优先依次压缩存入下标从 0 开始的一位数组 `A` 中。则 `A[20]` 对应的元素是( )
+
+- [ ] A. $M_{7, 7}$
+- [ ] B. $M_{8, 8}$
+- [ ] C. $M_{8, 7}$
+- [x] D. $M_{7, 8}$
+
+> 参考答案:D
+>
+> 三对角矩阵按列优先方式压缩存储。`A[20]` 是第 21 个元素。三对角矩阵的前 7 列共 $2 + 3 \times 6 = 20$ 个元素。因此第 21 个元素刚好是第八列的第一个元素,即 $M_{7, 8}$
+>
+> 咸鱼注:抱歉抱歉,第一次使用 MOOC 在线考试系统,MOOC 上选错了正确答案为 B,我自罚一杯奶茶。
+
+### 4. 【单选】(5 分)⼆叉树 $T$ 共有 4 个结点,若采⽤顺序存储结构保存,每个结点占 1 个存储单元,则存放该⼆叉树需要的存储单元数量最多是( )
+
+- [ ] A. 4
+- [ ] B. 7
+- [ ] C. 8
+- [x] D. 15
+
+> 参考答案:D
+>
+> 二叉树的顺序存储,需要将结点与「完全二叉树」对应。当每个分支结点都只有右孩子时,所需要的存储单元数量最多。二叉树的形态如下:
+>
+>
+>
+> 此题可以利用完全二叉树结点编号之间的关系来推导,对于一棵完全二叉树,若根节点编号从 1 开始,则每个分支节点 $i$ 的右孩子编号为 $2i + 1$。 由此可得,最下层的叶子结点对应完全二叉树的结点编号为 15。因此,该二叉树需要的存储单元数量最多是 15。
+>
+> 当然,也可以用另一个思路来计算,$h$ 层的满二叉树有总共有 $2h - 1$ 个结点,因此四层满二叉树
+总共有 15 个结点。
+
+### 5. 【单选】(5 分)某森林 `F` 对应的⼆叉树为 `T`,若 `T` 的先序遍历序列是 `a, b, d, c, e, g, f`,中序遍历序列是 `b, d, a, e, g, c, f`,则 `F` 中树的棵数是( )
+
+- [ ] A. 1
+- [ ] B. 2
+- [x] C. 3
+- [ ] D. 4
+
+> 参考答案:C
+>
+> 由于二叉树的前序遍历和中序遍历序列能确定唯一的一棵二叉树,因此本题可以确定二叉树 `T` 的结构。
+>
+>
+>
+> 逐层断掉 `T` 中最右侧的右子树,即可得到三棵树,因此森林 `F` 中树的棵数是 3。
+
+### 6. 【单选】(5 分)给定平衡二叉树如下图所示,插入关键字 23 后根结点中的关键字是( )
+
+
+
+- [ ] A. 16
+- [ ] B. 20
+- [ ] C. 23
+- [x] D. 25
+
+> 参考答案:D
+>
+> 将关键字 23 插入作为关键字25所在结点的左孩子后,该二叉树失衡,经过平衡调整后,该平衡二叉树变为如下图所示结构,根节点中的关键字为 25。
+>
+>
+
+### 7. 【单选】(5 分)若某⼆叉树有 5 个叶⼦结点,其权值分别为 10,12,16,21,30。则其最⼩的带权路径⻓度(WPL)是( )
+
+- [ ] A. 89
+- [x] B. 200
+- [ ] C. 208
+- [ ] D. 289
+
+> 参考答案:B
+>
+> 要求最小的 WPL,即考查哈夫曼树的构造,构造结果如下图所示,因此 $WPL = 2 \times (16 + 21 + 30) + 3 \times (10 + 12) = 200$。
+>
+>
+
+### 8. 【单选】(5 分)对于 $n (n \ge 2)$ 个字符构造的⼆叉哈夫曼树,每个字符结点的权值都⼤于 0 (但各节点权值可能相等)。则下列叙述错误的是 ( )
+
+- [x] A. 树中两个权值最⼩的结点⼀定是兄弟结点
+- [ ] B. 该哈夫曼树的最⼤⾼度是 $n$
+- [ ] C. 该哈夫曼树的结点总数为 $2n - 1$
+- [ ] D. 所有⾮叶结点的权值之和不⼩于所有叶结点的权值之和
+
+> 参考答案:A
+>
+> A 选项:该选项不严谨,若各个字符结点的权值都为 1,则所有的结点都是「权值最小的结点」,但不一定都是兄弟。
+>
+> B 选项:根据哈夫曼树的构造过程,包含 $n$ 个叶结点的哈夫曼树,最大高度为 $n$。
+>
+> C 选项:二叉哈夫曼树中,只有度为 2 和度为 0 的结点。度为 0 的结点数为 $n$,假设度为 2 的结点数为 $m$,则 $2m + 1 = m + n$,即 $m = n - 1$。因此该哈夫曼树的结点总数为 $2n - 1$。
+>
+> D 选项:根据哈夫曼树的构造过程可知,单独一个根节点的权值,就等于所有叶子结点的权值之和,再加上其他非叶结点的权值,一定大于所有叶子结点的权值之和。
+
+### 9. 【单选】(5 分)采用 KMP 算法进行模式匹配。主串 $S = 'ABCABCDABABCDABCDABDE'$,模式串$T = 'ABCDABD'$。当第三次发生「失配」(`S[j] != T[j]`) 时,单个字符间的累计比较次数是 ( )
+
+- [ ] A. 14
+- [ ] B. 13
+- [x] C. 12
+- [ ] D. 6
+
+> 参考答案:C
+>
+> 处理这个题目,并不需要求 `next` 数组,发生失配的时候,模式串往后滑就行。可以快速做题
+>
+> S = '**ABCA**BCDABABCDABCDABDE'
+> T = '**ABCD**ABD'`
+>
+> 第一次发生失配,累计比较了 4 次字符
+>
+> S = 'ABC**ABCDABA**BCDABCDABDE'
+> T = '**ABCDABD**'
+>
+> 第二次发生失配,累计比较了 $4 + 7$ 次字符
+>
+> S = 'ABCABCD**ABA**BCDABCDABDE'
+> T = '**ABC**DABD'
+>
+> 第三次发生失配,累计比较了 $4 + 7 + 1$ 次字符,即累计对比 12 次
+>
+> 咸鱼注:这个题目录入的时候也打错了,再自罚一杯,对不起!
+
+### 10. 【单选】(5 分)在⼀棵⾼度为 3、阶数为 3 的 B 树中,根为第⼀层,若第⼆层有 4 个关键字,则该树的结点个数最多是( )
+
+- [x] A. 11
+- [ ] B. 10
+- [ ] C. 9
+- [ ] D. 8
+
+> 参考答案:A
+>
+> 阶数为 3 的 B 树中,每个结点包含的关键字可以为 1 个或 2 个。本题中,要求第二层有 4 个关键字,则结点数最多的情况如下图所示,其中 A、B、C、D……表示关键字,最多可能有 11 个结点。
+>
+> ```mermaid
+> graph TB
+> 1[A B] --> 2[C D]
+> 1 --> 3[E]
+> 1 --> 4[F]
+> 2 --> 5[G]
+> 2 --> 6[H]
+> 2 --> 7[I]
+> 3 --> 8[J]
+> 3 --> 9[K]
+> 4 --> 10[L]
+> 4 --> 11[M]
+> ```
+
+### 11. 【单选】(5 分)已知初始为空的队列 `Q` 的⼀端能进⾏⼊队操作⼜能进⾏出队操作,另⼀端只能进⾏⼊队操作。若 `a` 的⼊队序列是 1,2,3,4,5。则不能得到的出队序列是( )
+
+- [ ] A. 5,4,3,1,2
+- [ ] B. 5,3,1,2,4
+- [ ] C. 4,2,1,3,5
+- [x] D. 4,1,3,2,5
+
+> 参考答案:D
+>
+> 题目应是一种输出受限的双端队列,因此根据选项 C 和 D,若 4 是第一个出队的元素,那么至少 1、2、3、4 已全部入队,则队列中 2 应该与 1 相邻,出队时顺序也应该相邻,所以选项 D 错误。
+
+## 综合应用题
+
+### 1. 字符串 `S` 的长度为 `n`,`S` 中的字符 `S[i]` 满足 `'A' <= S[i] <= 'Z'`,请设计一个时间上尽可能高效的算法,统计 `S` 中有多少个不同的字母。要求:
+
+#### (1)给出算法的基本设计思想。(6 分)
+
+可以使用一个数组 `a[26]` 保存 `A`~`Z` 是否出现过,`0` 表示已经未出现过,`>0` 表示出现过。扫描字符串 `S`,更新数组 `a`。然后用 `num` 统计有多少个不同的字母出现。
+
+#### (2)根据设计思想,采用 C 或 C++ 语言描述算法,关键之处给出注释。(10 分)
+
+```cpp
+int ans(char S[], int n) {
+ int j, a[26] = {};
+ int num = 0; // num 统计有几个不同的字母出现
+ for (int i = 0; i < n; i++) { // 扫描串 S
+ j = S[i] - 'A'; // j 表示是 A 开始的第几个字母,A 是第 0 个
+ a[j]++;
+ }
+ for (int i = 0; i < 26; i++) { // 统计
+ if (a[i] != 0) {
+ num++;
+ }
+ }
+ return num;
+}
+```
+
+#### (3)说明你所设计的算法的时间复杂度。
+
+空间复杂度主要是数组 `a[26]`,是常数所以是 $O(1)$。时间复杂度主要是两个循环,一个循环 $n$ 次,一个循环 26 次,所以是 $O(n)$。
+
+### 2、对于一棵非空平衡二叉树,其中任何一个节点的平衡因子只为 -1、0、1(平衡因子 = 左子树的高度 - 右子树的高度)
+
+#### (1)请写出二叉树的结点定义(`data` 域是 `int`)。
+
+```cpp
+typedef struct BiTNode {
+ int data;
+ struct BiTNode *lchild, *rchild;
+} BiTNode, *BiTree;
+
+typedef struct AVLNode {
+ int key;
+ struct AVLNode *lchild, *rchild;
+} AVLNode, *AVLTree;
+```
+
+#### (2)设 $a[h]$ 表示满足高为 $h$ 的平衡二叉树的最小节点数。$h = 1$ 时,只有根节点,$a[1] = 1$;$h = 2$ 时,$a[2] = 2$。请推导出 $a[h]$ 的递推关系式。
+
+$$
+a[h] = \begin{cases}
+h & h = 1, 2\\
+a[h - 1] + a[h - 2] + 1 & h \ge 3
+\end{cases}
+$$
+
+#### (3)对于下面这颗平衡二叉树,执行如下操作:删除 98,删除 115,插入37,插入 54。请分别画出每一步插入或者删除操作完成后的平衡二叉树。
+
+
+
+```mermaid
+graph TB
+subgraph 5
+28 ---|L| 23
+28 ---|R| 37
+23 ---|L| 15
+23 ---|R| 54
+37 ---|R| 34
+end
+subgraph 4
+d1(23) ---|L| d3(15)
+d1 ---|R| d2
+d2(37) ---|L| d5(28)
+d2 ---|R| d6(34)
+end
+subgraph 3
+c1(23) ---|L| c3(15)
+c1 ---|R| c2(34)
+c2 ---|L| c4(28)
+end
+subgraph 2
+b1(34) ---|L| b2(23)
+b1 ---|R| b3(115)
+b2 ---|L| b4(15)
+b2 ---|R| b5(28)
+end
+subgraph 1
+a1(34) ---|L| a2(23)
+a1 ---|R| a3(98)
+a2 ---|L| a4(15)
+a2 ---|R| a5(28)
+a3 ---|R| a6(115)
+end
+```
diff --git a/408/数据结构/期中考试.md b/408/数据结构/期中考试.md
deleted file mode 100644
index 1842fa1..0000000
--- a/408/数据结构/期中考试.md
+++ /dev/null
@@ -1,87 +0,0 @@
-### 1、字符串 `S` 的长度为 `n`,`S` 中的字符 `S[i]` 满足 `'A' <= S[i] <= 'Z'`,请设计一个时间上尽可能高效的算法,统计 `S` 中有多少个不同的字母。要求:
-
-#### (1)给出算法的基本设计思想。
-
-建立 `occur[26]`,初始值为 0,当字母出现时,相应位置设为 1,遍历字符串,输出 `occur` 中 1 的个数。
-
-#### (2)根据设计思想,采用 C 或 C++ 语言描述算法,关键之处给出注释。
-
-```cpp
-int occur[26]; // 建立数组表示字母是否出现,初始为 0
-int alphabet(char *S, int n) {
- for (int i = 0; i < n; i++) { // 依序读入 S 中字符
- occur[(int) S[i] - 65] = 1; // 字母出现时,数组相应位置变为 1('A' ~ 'Z' 的 ASCII 值为 65 ~ 90)
- }
- n = 0; // 初始化字母个数为 0
- for (int i = 0; i < 26; i++) { // 遍历 occur 数组
- n += occur[i]; // 计算有几个字母出现
- }
- return n;
-}
-```
-
-#### (3)说明你所设计的算法的时间复杂度。
-
-时间复杂度为 O(n)。
-
-### 2、对于一棵非空平衡二叉树,其中任何一个节点的平衡因子只为 -1、0、1(平衡因子 = 左子树的高度 - 右子树的高度)
-
-#### (1)请写出二叉树的结点定义(`data` 域是 `int`)。
-
-```cpp
-typedef struct BiTNode {
- int data;
- struct BiTNode *lchild, *rchild;
-} BiTNode, *BiTree;
-
-typedef struct AVLNode {
- int key;
- struct AVLNode *lchild, *rchild;
-} AVLNode, *AVLTree;
-```
-
-#### (2)设 $a[h]$ 表示满足高为 $h$ 的平衡二叉树的最小节点数。$h = 1$ 时,只有根节点,$a[1] = 1$;$h = 2$ 时,$a[2] = 2$。请推导出 $a[h]$ 的递推关系式。
-
-$$
-a[h] = \begin{cases}
-h & h = 1, 2\\
-a[h - 1] + a[h - 2] + 1 & h \ge 3
-\end{cases}
-$$
-
-#### (3)对于下面这颗平衡二叉树,执行如下操作:删除 98,删除 115,插入37,插入 54。请分别画出每一步插入或者删除操作完成后的平衡二叉树。
-
-```mermaid
-graph TB
-subgraph 5
-28 ---|L| 23
-28 ---|R| 37
-23 ---|L| 15
-23 ---|R| 54
-37 ---|R| 34
-end
-subgraph 4
-d1(23) ---|L| d3(15)
-d1 ---|R| d2
-d2(37) ---|L| d5(28)
-d2 ---|R| d6(34)
-end
-subgraph 3
-c1(23) ---|L| c3(15)
-c1 ---|R| c2(34)
-c2 ---|L| c4(28)
-end
-subgraph 2
-b1(34) ---|L| b2(23)
-b1 ---|R| b3(115)
-b2 ---|L| b4(15)
-b2 ---|R| b5(28)
-end
-subgraph 1
-a1(34) ---|L| a2(23)
-a1 ---|R| a3(98)
-a2 ---|L| a4(15)
-a2 ---|R| a5(28)
-a3 ---|R| a6(115)
-end
-```