更新了数据结构第六章部分
BIN
数据结构/第五章 树与二叉树/批注 2020-07-15 181759.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
74
数据结构/第五章 树与二叉树/真题解答.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# 习题5.5
|
||||
## T13 2012
|
||||
> 不会,以下为解答
|
||||
|
||||
1. 求最小合并次数类似于求最小带权路径长度,则联想到哈夫曼树。那么每次选择表集合中长度最小的两个表进行合并
|
||||
第一次 合并A、B
|
||||
第二次 合并AB和C
|
||||
第三次 合并D、E
|
||||
第四次 合并ABC和DE
|
||||
第五次 合并ABCDE和F
|
||||
|
||||
**合并两个有序表的最坏情况需要比较m+n-1次**
|
||||
则
|
||||
按合并顺序可以算出每次需要比较的次数
|
||||
|
||||
2. 合并表长不同的顺序表时,最坏情况下的比较次数依赖于合并的次序,则每次选择表长最短的两个表合并,可以获得最坏情况下的最小比较次数
|
||||
|
||||
> 原以为要考具体的元素级别的合并算法,结果是考表与表的合并……
|
||||
> 能获得启发就是:**合并两个有序表的最坏情况需要比较m+n-1次**
|
||||
|
||||
# 习题5.4
|
||||
## T4 2016
|
||||
1. `(k-1)*n+1`
|
||||
2. $$
|
||||
\begin{aligned}
|
||||
n_{max} &= \frac{1-k^h}{1-k} \\
|
||||
n_{min} &= k+\frac{1-k^{h-1}}{1-k}
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
# 习题5.3
|
||||
## T19 2014
|
||||
1. 采用深度优先的递归遍历搜索,记录递归层数,当访问到叶结点时把当前层数乘以叶结点权值,最后全部叶结点的带权路径长度值相加
|
||||
2. ```cpp
|
||||
typedef struct BiTreeNode{
|
||||
struct BiTreeNode *left;
|
||||
int weight;
|
||||
struct BiTreeNode *right;
|
||||
}BiTreeNode, *BiTree;
|
||||
```
|
||||
3. ```cpp
|
||||
i=1; //递归层数
|
||||
WPL=0; //带权路径长度
|
||||
void GetWPL(BiTree *p){
|
||||
if(p->left==NULL && p->right==NULL){ //叶结点
|
||||
i--;
|
||||
WPL+=i*p->weight;
|
||||
return ;
|
||||
}
|
||||
else{
|
||||
if(p->left!=NULL&&p->right==NULL){
|
||||
i++;
|
||||
GetWPL(p->left);
|
||||
}
|
||||
else(p->left==NULL&&p->right!=NULL){
|
||||
i++;
|
||||
GetWPL(p->right);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
## T20 2017
|
||||
1. 中序遍历二叉树,在递归访问某结点的左孩子之前输出一个左括号,在递归访问右孩子之后输出一个右括号
|
||||
2. ```cpp
|
||||
void func(BTree p){
|
||||
if(p!=NULL){
|
||||
cout<<'(';
|
||||
func(p->left);
|
||||
visit(p);
|
||||
func(p->right);
|
||||
cout<<')';
|
||||
}
|
||||
}
|
||||
```
|
||||
BIN
数据结构/第六章 图/1.png
Normal file
|
After Width: | Height: | Size: 358 KiB |
BIN
数据结构/第六章 图/2.1.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
BIN
数据结构/第六章 图/2.2.png
Normal file
|
After Width: | Height: | Size: 253 KiB |
BIN
数据结构/第六章 图/3.png
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
数据结构/第六章 图/4.png
Normal file
|
After Width: | Height: | Size: 220 KiB |
113
数据结构/第六章 图/图的存储和基本操作.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# 图的存储
|
||||
## 邻接矩阵法
|
||||
用一个一维数组存储顶点信息,用一个二维数组存储图中边的信息
|
||||
|
||||
结点数为n的图,其邻接矩阵A是n×n的,A[i][j]表示顶点i和顶点j之间的边,有向图中A[i][j]与A[j][i]一般不同
|
||||
|
||||
不带权的图:
|
||||
$$A[i][j]=
|
||||
\left\{\begin{matrix}
|
||||
1,若 (v_i,v_j)或<v_i,v_j>是E(G)中的边\\
|
||||
0,若 (v_i,v_j)或<v_i,v_j>不是E(G)中的边\\
|
||||
\end{matrix}\right.
|
||||
$$
|
||||
带权图:
|
||||
$$A[i][j]=
|
||||
\left\{\begin{matrix}
|
||||
w_{ij},若 (v_i,v_j)或<v_i,v_j>是E(G)中的边\\
|
||||
0或\infty,若 (v_i,v_j)或<v_i,v_j>不是E(G)中的边\\
|
||||
\end{matrix}\right.
|
||||
$$
|
||||
|
||||
邻接矩阵法的存储结构定义
|
||||
```cpp
|
||||
#define MaxVertexNum 100
|
||||
typedef char VertexType;
|
||||
typedef int EdgeType;
|
||||
typedef struct{
|
||||
VertexType Vex[MaxVertexNum];
|
||||
EdgeType Edge[MaxVertexNum][MaxVertexNum];
|
||||
int vexnum, arcnum; //图的当前顶点数和弧数
|
||||
}MGraph;
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 邻接表法
|
||||
邻接表是指对每一个顶点建立一个单链表,第i个单链表中的结点代表了依附于顶点i的边(无向图),或是代表了以i为弧尾的边(有向图)
|
||||
|
||||
```cpp
|
||||
#define MaxVertexNum 100
|
||||
typedef struct ArcNode{ //边表结点
|
||||
int adjvex; //该弧指向的顶点的位置
|
||||
struct ArcNode *next;
|
||||
//InfoType info; 边权值
|
||||
}ArcNode;
|
||||
typedef struct VNode{ //顶点表结点
|
||||
VertexType data;
|
||||
ArcNode *first;
|
||||
}VNode, AdjList[MaxVertexNum];
|
||||
typedef struct{
|
||||
AdjList vertices; //邻接表
|
||||
int vexnum,arcnum; //图的顶点数和弧数
|
||||
}ALGraph;
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
## 十字链表法
|
||||
> 用于有向图
|
||||
|
||||
弧结点有5个域:
|
||||
* tailvex, headvex指向弧头结点和弧尾结点
|
||||
* hlink指向弧头相同的下一条弧
|
||||
* tlink指向弧尾相同的下一条弧
|
||||
* info包括了弧的相关信息
|
||||
|
||||
顶点结点有3个域:
|
||||
* data存放顶点有关信息
|
||||
* firstin和firstout指向以该节点为弧头或弧尾的第一个弧结点
|
||||
|
||||

|
||||
|
||||
## 邻接多重表
|
||||
> 用于无向图
|
||||
|
||||
与十字链表类似,每个边和顶点都有顶点
|
||||
|
||||
边结点:
|
||||
* Mark标记是否被搜索过
|
||||
* ivex指向该边依附的i结点位置
|
||||
* jvex指向该边依附的j结点位置
|
||||
* ilink指向下一条依附于i结点的边
|
||||
* jlink指向下一条依附于j结点的边
|
||||
* info表示边信息
|
||||
|
||||
顶点结点:
|
||||
* data代表顶点信息
|
||||
* firstedge指向第一条依附于该顶点的边
|
||||
|
||||

|
||||
|
||||
# 图的基本操作
|
||||
- Adjacent(G, x, y)
|
||||
- 判断图G是否存在边(x,y)或<x,y>
|
||||
- Neighbors(G, x)
|
||||
- 列出G中与结点x邻接的边
|
||||
- InsertVertex(G, x)
|
||||
- 在G中插入顶点x
|
||||
- DeleteVertex(G, x)
|
||||
- 在G中删除顶点x
|
||||
- AddEdge(G, x, y)
|
||||
- 若G中不存在边(x,y)或<x,y>,则添加该边
|
||||
- RemoveEdge(G, x, y)
|
||||
- 若G中存在边(x,y)或<x,y>,则删除该边
|
||||
- FirstNeighbor(G, x)
|
||||
- 求G中顶点x的第一个邻接点,返回顶点号;出现错误则返回-1
|
||||
- NextNeighbor(G, x, y)
|
||||
- 设y为x的一个邻接点,返回除y的下一个邻接点号;其他情况返回-1
|
||||
- Get_edge_value(G, x, y)
|
||||
- 返回边(x,y)或<x,y>的权值
|
||||
- Set_edge_value(G, x, y, v)
|
||||
- 设置边(x,y)或<x,y>的权值为v
|
||||
84
数据结构/第六章 图/图的遍历.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# 广度优先搜索
|
||||
1. **基本思想**:从一个选定的顶点v出发,依次访问v的邻接结点,再从这些结点出发,去访问与他们邻接且没有被访问过的结点,重复这个过程直到图中所有的结点都被访问过
|
||||
|
||||
2. 伪代码:
|
||||
```cpp
|
||||
bool visited[MAX_VERTEX_NUM]; //标记数组
|
||||
void BFSTraverse(Graph G){
|
||||
for(i=0;i<G.vexnum;++i){ //初始化标记数组
|
||||
visited[i]=FALSE;
|
||||
}
|
||||
InitQueue(Q); //辅助队列
|
||||
for(i=0;i<G.vexnum;++i){ //遍历图的所有结点
|
||||
if(!visited[i]){ //如果未访问过,则调用广搜
|
||||
BFS(G,i); //这种做法是为了防止图不是一个连通图
|
||||
}
|
||||
}
|
||||
}
|
||||
void BFS(Graph G, int v){
|
||||
visit(v); //访问结点v
|
||||
visited[v]=TRUE; //立即标记访问过该节点
|
||||
Enqueue(Q,v); //第一结点入队
|
||||
while(!isEmpty(Q)){
|
||||
DeQueue(Q,v); //对队列头v进行处理
|
||||
for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w)){
|
||||
//检测v的所有邻接点
|
||||
if(!visited[w]){ //对每一个v的未曾访问过的邻接点w
|
||||
visit(w); //访问
|
||||
visited[w]=TRUE;//标记
|
||||
EnQueue(Q,w); //入队
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
3. 性质分析:
|
||||
- 复杂度分析:
|
||||
- **时间复杂度** : $O(|V|^2)$
|
||||
- **空间复杂度** : $O(|V|)$
|
||||
- BFS是树的层次遍历的扩充
|
||||
|
||||
|
||||
|
||||
# 深度优先搜索
|
||||
1. **基本思想**:从一个顶点v出发,访问其邻接且未访问过的任意一个w1,继续访问w1的邻接点中的任意一个w2,如此下去直到无法继续,回退到最近访问过的结点,若它还有未访问过的邻接结点,则对其使用深搜。
|
||||
|
||||
2. 伪代码:
|
||||
```cpp
|
||||
bool visited[MAX_VERTEX_NUM]; //新建标记数组
|
||||
void DFSTraverse(Graph G){
|
||||
for(v=0;v<G.vexnum;++v){ //初始化标记数组
|
||||
visited[v]=FALSE;
|
||||
}
|
||||
for(v=0;v<G.vexnum;++v){ //对图的每个连通分量进行深搜
|
||||
if(!visited[i]){
|
||||
DFS(G,v);
|
||||
}
|
||||
}
|
||||
}
|
||||
void DFS(Graph G, int v){
|
||||
visit(i);
|
||||
visited[i]=TRUE;
|
||||
for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)){
|
||||
//对于v的每一个邻接结点w
|
||||
if(!visited[w]){
|
||||
DFS(G,w);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. 性质分析:
|
||||
- 复杂度分析:
|
||||
- **时间复杂度** :
|
||||
- 邻接矩阵表达: $O(|V|^2)$
|
||||
- 邻接表表达:$O(|V|+|E|)$
|
||||
- **空间复杂度** : $O(|V|)$
|
||||
- DFS是树的先序遍历的扩展
|
||||
|
||||
> 图、树、森林的等效遍历方式
|
||||
> | 树 | 森林 | 二叉树 | 图 |
|
||||
> | :-: | :-: | :-: | :-: |
|
||||
> | 先根遍历 | 先序遍历 | 先序遍历 | DFS |
|
||||
> | 后根遍历 | 中序遍历 | 中序遍历 | x |
|
||||
> | 层次遍历 | x | 层次遍历 | BFS |
|
||||
BIN
数据结构/第六章 图/批注 2020-07-23 163518.png
Normal file
|
After Width: | Height: | Size: 24 KiB |