feat: 新增数据结构实验 7 和实验 8
This commit is contained in:
@@ -16,7 +16,9 @@
|
|||||||
├── test3 # 实验3
|
├── test3 # 实验3
|
||||||
├── test4 # 实验4
|
├── test4 # 实验4
|
||||||
├── test5 # 实验5
|
├── test5 # 实验5
|
||||||
└── test6 # 实验6
|
├── test6 # 实验6
|
||||||
|
├── test7 # 实验7
|
||||||
|
└── test8 # 实验8
|
||||||
```
|
```
|
||||||
### 实验结果
|
### 实验结果
|
||||||
- 实验 1
|
- 实验 1
|
||||||
@@ -42,3 +44,11 @@
|
|||||||
- 实验 6
|
- 实验 6
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
- 实验 7
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 实验 8
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
BIN
DataStructure/images/test7.png
Normal file
BIN
DataStructure/images/test7.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
BIN
DataStructure/images/test8.png
Normal file
BIN
DataStructure/images/test8.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 432 KiB |
133
DataStructure/test7/实验七.cpp
Normal file
133
DataStructure/test7/实验七.cpp
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int inf = 1000;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int weight; // 结点权值
|
||||||
|
int parent, lchild, rchild; // 结点的双亲、左孩子、右孩子的下标
|
||||||
|
char ch; // 字符
|
||||||
|
} HTNode, *HuffmanTree;
|
||||||
|
|
||||||
|
// 查找
|
||||||
|
int Find(HuffmanTree HT, int n)
|
||||||
|
{
|
||||||
|
int min = 0;
|
||||||
|
for (int i = 1; i <= n; i++)
|
||||||
|
{
|
||||||
|
if (HT[i].weight < HT[min].weight && HT[i].parent == 0)
|
||||||
|
min = i;
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择
|
||||||
|
void select(HuffmanTree HT, int n, int &s1, int &s2) // 传入参数n=k-1
|
||||||
|
{
|
||||||
|
s1 = Find(HT, n); // a、在HT[k](1≤k≤i-1)中选择两个其双亲域为0, 且权值最小的结点,并返回它们在HT中的序号s1和s2
|
||||||
|
HT[s1].parent = n + 1; // b、得到新结点n + 1,从森林中删除s1,s2,将s1,s2的双亲域由0改为k (即n+1)
|
||||||
|
s2 = Find(HT, n);
|
||||||
|
HT[s2].parent = n + 1; // b、得到新结点n + 1,从森林中删除s1,s2,将s1,s2的双亲域由0改为k (即n+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造
|
||||||
|
void CreatHuffmanTree(HuffmanTree &HT, int weight[], char c[], int n) // char c[100]; 字母
|
||||||
|
{
|
||||||
|
if (n <= 1)
|
||||||
|
return;
|
||||||
|
int m = 2 * n - 1; // 数组存储2n-1个元素
|
||||||
|
HT = new HTNode[m + 1]; // 0号单元未用,所以需要开辟m+1个单元,HT[m]表示根结点
|
||||||
|
for (int i = 1; i <= m; ++i) // 将2n-1个元素的lch、 rch、 parent初始化为0, ch字符全部初始化为#
|
||||||
|
{
|
||||||
|
// todo list 处理parent 、lchild 、rchild
|
||||||
|
HT[i].parent = 0;
|
||||||
|
HT[i].lchild = 0;
|
||||||
|
HT[i].rchild = 0;
|
||||||
|
HT[i].ch = '#';
|
||||||
|
}
|
||||||
|
HT[0].weight = inf; // int inf = 1000;
|
||||||
|
|
||||||
|
for (int j = 1; j <= n; ++j)
|
||||||
|
{
|
||||||
|
// todo list //获取 前n个单元中叶子节点的 weight值
|
||||||
|
HT[j].weight = weight[j];
|
||||||
|
HT[j].ch = c[j]; // 获取 前n个单元中叶子节点的 字符
|
||||||
|
}
|
||||||
|
for (int k = n + 1; k <= m; ++k) // 合并产生n-1个结点——构造Huffman树
|
||||||
|
{
|
||||||
|
int s1, s2;
|
||||||
|
select(HT, k - 1, s1, s2); // 选择两个需要求和的下标
|
||||||
|
// todo list //c、s1,s2分别作为k的左右孩子
|
||||||
|
HT[k].lchild = s1;
|
||||||
|
HT[k].rchild = s2;
|
||||||
|
// todo list //c、k 的权值为左右孩子权值之和
|
||||||
|
HT[k].weight = HT[s1].weight + HT[s2].weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出哈夫曼树
|
||||||
|
void DisplayHF(HuffmanTree HT, int r)
|
||||||
|
{
|
||||||
|
printf("%c %d\n", HT[r].ch, HT[r].weight);
|
||||||
|
|
||||||
|
int s1 = HT[r].lchild;
|
||||||
|
int s2 = HT[r].rchild;
|
||||||
|
if (s1 != 0)
|
||||||
|
DisplayHF(HT, s1);
|
||||||
|
if (s2 != 0)
|
||||||
|
DisplayHF(HT, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出哈夫曼编码
|
||||||
|
void DisplayHFCode(HuffmanTree HT, int r, int arr[], int top)
|
||||||
|
{
|
||||||
|
int s1 = HT[r].lchild; // 获取当前节点的左孩子索引赋值给s1
|
||||||
|
int s2 = HT[r].rchild; // 获取当前节点的右孩子索引赋值给s2
|
||||||
|
|
||||||
|
if (HT[r].lchild != 0)
|
||||||
|
{ // 左孩子存在
|
||||||
|
arr[top] = 0; // 在路径数组arr的当前位置top存入0,表示走向左孩子
|
||||||
|
DisplayHFCode(HT, s1, arr, top + 1); // 递归调用DisplayHFCode函数,处理左孩子节点,同时top加1
|
||||||
|
}
|
||||||
|
if (HT[r].rchild != 0)
|
||||||
|
{ // 右孩子存在
|
||||||
|
arr[top] = 1; // 在路径数组arr的当前位置top存入1,表示走向右孩子
|
||||||
|
DisplayHFCode(HT, s2, arr, top + 1); // 递归调用DisplayHFCode函数,处理右孩子节点,同时top加1
|
||||||
|
}
|
||||||
|
if (HT[r].lchild == 0 && HT[r].rchild == 0)
|
||||||
|
{ // 叶子节点
|
||||||
|
printf("字符 %c 的编码: ", HT[r].ch); // 打印当前叶子节点对应的字符
|
||||||
|
for (int i = 0; i < top; ++i)
|
||||||
|
{ // 遍历路径数组arr,从0到top-1
|
||||||
|
printf("%d", arr[i]); // 打印路径数组中的每个元素,即字符的哈夫曼编码
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
HuffmanTree HT;
|
||||||
|
int a[100]; // 权值
|
||||||
|
char c[100]; // 字母
|
||||||
|
int arr[100]; // arr:用于存储从根结点到当前结点的路径上的0和1的数组
|
||||||
|
int top = 0; // top: arr数组的当前索引,表示已经存储到的路径的长度
|
||||||
|
|
||||||
|
printf("请输入七组数据!(字母 权值)\n");
|
||||||
|
for (int i = 1; i <= 7; i++)
|
||||||
|
{
|
||||||
|
scanf("%c %d", &c[i], &a[i]);
|
||||||
|
getchar(); // 吸收换行符,避免影响下一次输入
|
||||||
|
}
|
||||||
|
CreatHuffmanTree(HT, a, c, 7);
|
||||||
|
printf("哈夫曼树先序遍历序列为(字母 权值):\n");
|
||||||
|
printf("新生成结点用‘#’标记\n");
|
||||||
|
DisplayHF(HT, 7 * 2 - 1); // 根节点下标为2n-1=13
|
||||||
|
|
||||||
|
printf("哈夫曼编码为:\n");
|
||||||
|
DisplayHFCode(HT, 7 * 2 - 1, arr, top);
|
||||||
|
|
||||||
|
// 释放动态分配的内存(避免内存泄漏)
|
||||||
|
delete[] HT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
228
DataStructure/test8/实验八.cpp
Normal file
228
DataStructure/test8/实验八.cpp
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MaxSize 8
|
||||||
|
|
||||||
|
typedef struct ArcNode
|
||||||
|
{ // 【边结点】
|
||||||
|
int adjvex; // 该边所指向的顶点的位置
|
||||||
|
struct ArcNode *nextarc; // 指向下一条边的指针
|
||||||
|
} ArcNode;
|
||||||
|
|
||||||
|
typedef struct VNode
|
||||||
|
{ // 【表头结点】
|
||||||
|
char data[3]; // 顶点信息——每个顶点的数据是一个由3个字符组成的字符串(或字符数组)V0,V1
|
||||||
|
ArcNode *firstarc; // 指向第一条依附该顶点的边的指针
|
||||||
|
} VNode;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
VNode vertices[MaxSize]; // 邻接表(vertices为数组名)
|
||||||
|
int vexnum, arcnum; // 图的当前顶点数和边数
|
||||||
|
} ALGragh;
|
||||||
|
|
||||||
|
// 1、构建图:参考P151算法6.2
|
||||||
|
void InitList(ALGragh &G, char a[][3])
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for (i = 0; i < G.vexnum; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 3; j++)
|
||||||
|
// todo list //输入顶点值
|
||||||
|
G.vertices[i].data[j] = a[i][j];
|
||||||
|
// todo list //初始化表头结点的指针域为NULL
|
||||||
|
G.vertices[i].firstarc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("请输入各边所依附的两个顶点的位置\n");
|
||||||
|
for (int k = 0; k < G.arcnum; k++)
|
||||||
|
{
|
||||||
|
scanf("%d %d", &i, &j);
|
||||||
|
// 生成一个新的边结点*p1:
|
||||||
|
ArcNode *p1 = (ArcNode *)malloc(sizeof(struct ArcNode));
|
||||||
|
// todo list 设此邻接点序号为j,并将新结点*p1插入顶点vi的边表头部(头插法)
|
||||||
|
p1->adjvex = j;
|
||||||
|
p1->nextarc = G.vertices[i].firstarc;
|
||||||
|
G.vertices[i].firstarc = p1;
|
||||||
|
|
||||||
|
// 生成另一个对称的新的边结点*p2:
|
||||||
|
ArcNode *p2 = (ArcNode *)malloc(sizeof(struct ArcNode));
|
||||||
|
// todo list 设此邻接点序号为i,并将新结点*p2插入顶点vj的边表头部(头插法)
|
||||||
|
p2->adjvex = i;
|
||||||
|
p2->nextarc = G.vertices[j].firstarc;
|
||||||
|
G.vertices[j].firstarc = p2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2、输出邻接表
|
||||||
|
void PrintInf(ALGragh G)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
ArcNode *p; // struct ArcNode* p;
|
||||||
|
printf("输出图的邻接表:\n");
|
||||||
|
for (i = 0; i < G.vexnum; i++)
|
||||||
|
{ // G.vexnum表示图中的顶点数量。
|
||||||
|
printf("%s ", G.vertices[i].data); // 打印当前顶点 i 的数据 (%s 被用于表示待插入的数据是字符串类型)
|
||||||
|
// for (// todo list) //for循环遍历当前顶点 i 的所有邻接顶点,并打印这些邻接顶点。
|
||||||
|
for (p = G.vertices[i].firstarc; p != NULL; p = p->nextarc)
|
||||||
|
printf("%d ", p->adjvex);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3、对采用【邻接表】表示的图,做深度优先遍历:参考P157算法6.6
|
||||||
|
void DFS_AL(ALGragh G, int visited[], int v)
|
||||||
|
{
|
||||||
|
printf("%s ", G.vertices[v].data); // 访问第 v 个顶点
|
||||||
|
ArcNode *p;
|
||||||
|
int w;
|
||||||
|
visited[v] = 1;
|
||||||
|
|
||||||
|
// todo list //将 p 初始化为指向顶点 v 的第一个邻接点的指针
|
||||||
|
p = G.vertices[v].firstarc;
|
||||||
|
// todo list //while循环:对v未被访问的邻接顶点w递归调用DFSTraverse 函数;并寻找v相对于w的下一个邻接点
|
||||||
|
while (p != NULL)
|
||||||
|
{
|
||||||
|
w = p->adjvex;
|
||||||
|
if (!visited[w])
|
||||||
|
DFS_AL(G, visited, w);
|
||||||
|
p = p->nextarc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4、深度优先遍历非连通图(也兼容连通图) : 参考P156算法6.4 (可用于计算连通分量的个数,但需要增加count变量,如下算法5)
|
||||||
|
void DFSTraverse_AL(ALGragh G, int visited[])
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
for (v = 0; v < G.vexnum; v++) // 初始化标记数组,置为0
|
||||||
|
visited[v] = 0;
|
||||||
|
for (v = 0; v < G.vexnum; v++)
|
||||||
|
// todo list 如果有顶点没有被访问,那就以它为起点遍历所在的连通分量
|
||||||
|
if (!visited[v])
|
||||||
|
DFS_AL(G, visited, v);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5、计算连通分量的个数
|
||||||
|
void Count(ALGragh G, int visited[])
|
||||||
|
{
|
||||||
|
int count = 0, v;
|
||||||
|
for (v = 0; v < G.vexnum; v++) // 初始化标记数组,置为0
|
||||||
|
visited[v] = 0;
|
||||||
|
for (v = 0; v < G.vexnum; v++)
|
||||||
|
// todo list 如果有顶点没有被访问,那就以它为起点遍历所在的连通分量,连通分量个数加一
|
||||||
|
if (!visited[v])
|
||||||
|
{
|
||||||
|
DFS_AL(G, visited, v);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
printf("连通分量个数:%d\n", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 思考1
|
||||||
|
// 对采用【邻接矩阵】表示的图,做深度先遍历:
|
||||||
|
void DFS_AM(ALGragh G, int visited[], int v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
// 深度优先遍历非连通图
|
||||||
|
void DFSTraverse_AM(ALGragh G, int visited[], int v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// 思考2
|
||||||
|
// 对采用【邻接表】表示的图,做广度先遍历:
|
||||||
|
void BFS_AL(ALGragh G, int visited[], int v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
// 广度优先遍历非连通图
|
||||||
|
void BFSTraverse_AL(ALGragh G, int visited[], int v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// 思考3
|
||||||
|
// 对采用【邻接矩阵】表示的图,做广度先遍历:
|
||||||
|
void BFS_AM(ALGragh G, int visited[], int v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
// 广度优先遍历非连通图
|
||||||
|
void BFSTraverse_AM(ALGragh G, int visited[], int v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6、判断有无路径可达
|
||||||
|
void Judge(ALGragh G, int visited[], int v, int u)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < G.vexnum; i++)
|
||||||
|
visited[i] = 0;
|
||||||
|
// todo list 以v作为起点,做深度优先遍历图,在此过程中不断将所有相互连接的邻接结点的visited[u]更新为1
|
||||||
|
DFS_AL(G, visited, v);
|
||||||
|
if (visited[u] == 1)
|
||||||
|
{
|
||||||
|
printf("\n");
|
||||||
|
printf("V%d与V%d有路径可达!\n", v, u);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("\n");
|
||||||
|
printf("V%d与V%d无路径可达!\n", v, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int v, u; // j是边的数目,v、u为顶点位置
|
||||||
|
int choose = -1;
|
||||||
|
// a是一个二维字符数组,存储顶点信息(字符串还得保存结尾的空字符\0,因此列数需要设为3)
|
||||||
|
char a[MaxSize][3] = {"V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7"};
|
||||||
|
int visited[MaxSize] = {0};
|
||||||
|
ALGragh G;
|
||||||
|
G.vexnum = MaxSize;
|
||||||
|
|
||||||
|
printf("*****************************************************\n");
|
||||||
|
printf("********** 实验八 *******\n");
|
||||||
|
printf("*****************************************************\n");
|
||||||
|
printf("********** 1.构建图 *******\n");
|
||||||
|
printf("********** 2.输出邻接表 *******\n");
|
||||||
|
printf("********** 3.深度优先遍历的结果 *******\n");
|
||||||
|
printf("********** 4.判断两个点之间是否有路径可达 *******\n");
|
||||||
|
printf("********** 5.输出连通分量的个数 *******\n");
|
||||||
|
printf("********** 0.退出 *******\n");
|
||||||
|
printf("*****************************************************\n");
|
||||||
|
while (choose)
|
||||||
|
{
|
||||||
|
printf("请输入你的选择项:");
|
||||||
|
scanf("%d", &choose);
|
||||||
|
switch (choose)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
printf("输入边数:");
|
||||||
|
scanf("%d", &G.arcnum);
|
||||||
|
InitList(G, a);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
PrintInf(G);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
printf("深度优先遍历结果:");
|
||||||
|
DFSTraverse_AL(G, visited); // 3 深度优先遍历图
|
||||||
|
// DFS_AL(G, visited,v); //如果是一个连通图,直接调用 DFS_AL也可以得到正确结果
|
||||||
|
printf("\n");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
printf("输入要判断的两个点:");
|
||||||
|
scanf("%d %d", &v, &u);
|
||||||
|
Judge(G, visited, v, u);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
Count(G, visited);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -20,5 +20,6 @@
|
|||||||
├── test4 # 实验4
|
├── test4 # 实验4
|
||||||
├── test5 # 实验5
|
├── test5 # 实验5
|
||||||
├── test6 # 实验6
|
├── test6 # 实验6
|
||||||
└── test7 # 实验7
|
├── test7 # 实验7
|
||||||
|
└── test8 # 实验8
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user