1
1
mirror of https://github.com/ParkMoonJ/KaoYan.git synced 2026-11-03 22:34:56 +08:00

Update 《数据结构》综合应用题.md

This commit is contained in:
ParkMoonJ
2021-11-18 18:55:17 +08:00
parent e331b0f2bc
commit 20ab947e60

View File

@@ -1,6 +1,6 @@
# 《数据结构》综合应用题
## [2021 - 41]
## 【2021 - 41】
已知无向连通图 $G$ 由顶点集 $V$ 和边集 $E$ 组成,$|E| > 0$,当 $G$ 中度为奇数的顶点个数为不大于 2 的偶数时,$G$ 存在包含所有边且长度为 $|E|$ 的路径(称为 EL 路径)。设图 $G$ 采用邻接矩阵存储,类型定义如下:
@@ -40,7 +40,7 @@ int IsExistEL(MGraph G){
// 空间复杂度:O(1)。
```
## [2021 - 42]
## 【2021 - 42】
已知某排序算法如下:
@@ -70,7 +70,7 @@ void cmpCountSort(int a[], int b[], int n){
2. $\frac{n * (n - 1)}{2}$
3. 不是,不能保证两元素相同时,先出现的元素在前,应改为 `if (a[i] <= a[j]) count[j]++;`
## [2020 - 41]
## 【2020 - 41】
定义三元组 $(a, b, c)$(其中 $a, b, c$ 均为正数)的距离 $D = |a - b| + |b - c| + |c - a|$。给定 3 个非空整数集合 $S_1$、$S_2$ 和 $S_3$,按升序分别存储在 3 个数组中。设计一个尽可能高效的算法,计算并输出所有可能的三元组 $(a, b, c) (a \in S_1, b \in S_2, c \in S_3)$ 中的最小距离。例如 $S_1 = \{-1, 0, 9\}, S_2 = \{-25, -10, 10, 11\}, S_3 = \{2, 9, 17, 30, 41\}$,则最小距离为 2,相应的三元组为 $\{9, 10, 9\}$。要求:
@@ -113,7 +113,7 @@ int Ans(int a[], int la, int b[], int lb, int c[], int lc){
---
## [2020 - 42]
## 【2020 - 42】
若任一个字符的编码都不是其他字符编码的前缀,则称这种编码具有前缀特性。现有某字符集(字符个数 >= 2)的不等长编码,每个字符的编码均为二进制的 0、1 序列,最长为 $L$ 位,且具有前缀特性。请回答下列问题:
@@ -124,4 +124,89 @@ int Ans(int a[], int la, int b[], int lb, int c[], int lc){
---
1. 使用一棵二叉树保存字符集中各字符的编码,每个编码对应于从根开始到达某叶结点的一条路径,路径长度等于编码位数,路径到达的叶结点中保存该编码对应的字符。
2. 从左至右依次扫描
2. 从左至右依次扫描 0/1 串中的各位。从根开始,根据串中当前位沿当前节点的左子指针或右子指针下移,直到移动到叶结点为止。输出叶结点中保存的字符。然后从根开始重复这个过程,直到扫描到 0/1 串结束,译码完成。
3. 二叉树即可用于保存各字符的编码,又可用于检测编码是否具有前缀特性。判定编码是否具有前缀特性的过程,也是构建二叉树的进程。初始时,二叉树中仅含有根结点,其左子指针和右子指针均为空。
依次读入每个编码 C,建立/寻找从根开始对应于该编码的一条路径,过程如下:
对每个编码,从左至右扫描 C 的各位,根据 C 的当前位(0 或 1)沿结点的指针(左子指针或右子指针)向下移动。当遇到空指针时,创建新结点,让空指针指向该新结点并继续移动。沿指针移动的过程中,可能遇到三种情况:
- 若遇到了叶结点(非根),则表明不具有前缀特性,返回。
- 若在处理 C 的所有位过程中,均没有创建新结点,则表明不具有前缀特性,返回。
- 若在处理 C 的最后一个编码位时创建了新结点,则继续验证下一个编码。
若所有编码均通过验证,则编码具有前缀特性。
## 【2019 - 41】
设线性表 $L = (a_!, a_2, a_3, \cdots, a_{n - 2}, a_{n - 1}, a_n)$ 采用带头结点的单链表保存,链表中的结点定义如下:
```c
typedef struct node{
int data;
struct node *next;
}NODE;
```
请设计一个空间复杂度为 $O(1)$ 且时间上尽可能高效的算法,重新排列 $L$ 中的各结点,得到线性表 $L' = (a_1, a_n, a_2, a_{n-1}, a_3, a_{n - 2}, \cdots)$。要求:
1. 给出算法的基本设计思想。
2. 根据设计思想,采用 C 或 C++ 语言描述算法,关键之处给出注释。
3. 说明你所设计算法的时间复杂度。
---
```cpp
void Ans(NODE *head){
NODE *p, *q, *r, *s;
// 寻找中间结点
p = q = head;
while (p->next) {
p = p->next; // p 走一步
q = q->next;
if (q->next) q = q->next; // q 走两步
}
q = p->next;
p->next = NULL; // p 为中间结点,q 为后半段链表的首结点
// 将链表后半段逆置
while (q) {
r = q->next;
q->next = p->next;
p->next = q;
q = r;
}
// 建立新链表 L’
s = h->next;
q = p->next;
p->next = NULL;
while(q) {
r = q->next;
q->next = s->next;
s->next = q;
s = q->next;
q = r
}
}
```
时间复杂度:$O(n)$。
## 【2019 - 42】
请设计一个队列,要求满足:
- 初始时对列为空;
- 入队时,允许增加队列占用空间;
- 出队后,出队元素所占用的空间可重复使用,即整个队列所占用的空间只增不减;
- 入队操作和出队操作的时间复杂度始终保持为 $O(1)$。
请回答下列问题:
1. 该队列是应选择链式存储结构,还是应选择顺序存储结构?
2. 画出该队列的初始状态,并给出判断队空和队满的条件。
3. 画出第一个元素入队后的队列状态。
4. 给出入队操作和出队操作的基本过程。
---
1. 链式存储结构
2. 循环链式队列