实验四 通信网中的算法问题—深入优先算法和广度优先算法(节点遍历)
一. 引言
在通信网络中,节点遍历是一项重要的任务,它有助于理解网络的拓扑结构、识别潜在问题和进行各种分析。深度优先搜索算法和广度优先搜索算法是两种常用的图遍历方法,它们可以帮助我们了解网络中的节点之间的连接关系。
二. 系统设计要求
实验要求:
1、以任意节点为起点,利用深度优先搜索算法,计算附图的遍历顺序并打印输出(是否可以用2种不同的实现方法);
2、以任意节点为起点,利用广度优先搜索算法,计算附图的遍历顺序并打印输出(是否可以用2种不同的实现方法);
注意:
1、请转换附件的图形为输入数据格式(附在实验报告上);
2、请打印的时候把节点编号、节点名称按照遍历的顺序打印.
具体显示内容:
1、节点数**
2、节点编号及名称**
3、边数**
4、深度优先搜索结果:****(例如:1、重庆;4、上海。。。。。。。)
5、广度优先搜搜结果:****
6、是连通图,所有节点都遍历;
不是连通图,**节点无法遍历;
三. 设计思路与方案
1.程序流程图设计
2.全局变量及结构体
#define CITY_NUM 10
#define connect 1
#define unconnect 0 // 表示无连接
int graph[CITY_NUM][CITY_NUM]; // 城市之间的距离
int p[CITY_NUM]; // 前驱节点数组,存储最短路径的前驱节点
int S[CITY_NUM]; // 标记已访问的顶点
char cities[CITY_NUM][20] =
{
"重庆",
"北京",
"成都",
"上海",
"深圳",
"杭州",
"广州",
"武汉",
"天津",
"南京",
};
3.算法设计
3.1整体代码
#include <stdio.h>
#define CITY_NUM 10
#define connect 1
#define unconnect 0 // 表示无连接
int graph[CITY_NUM][CITY_NUM]; // 城市之间的距离
int p[CITY_NUM]; // 前驱节点数组,存储最短路径的前驱节点
int S[CITY_NUM]; // 标记已访问的顶点
char cities[CITY_NUM][20] =
{
"重庆",
"北京",
"成都",
"上海",
"深圳",
"杭州",
"广州",
"武汉",
"天津",
"南京",
};
void fileop(void)
{
FILE *fp;
int i, j;
int from, to;
if ((fp = fopen("input1.txt", "r")) == NULL)
{
printf("文件打开失败");
}
else
{
// 初始化图,将每个节点之间权值设为0表示为未连接
for (i = 0; i < CITY_NUM; i++)
{
for (j = 0; j < CITY_NUM; j++)
{
graph[i][j] = unconnect;
}
}
// 读取文件节点之间的权值并赋值
while (fscanf(fp, "%d %d", &from, &to) == 2)
{
graph[from - 1][to - 1] = connect;
graph[to - 1][from - 1] = connect;
}
fclose(fp);
}
}
void printCities()
{
printf("节点的编号及名称:\n");
for (int i = 0; i < CITY_NUM; i++)
{
printf("节点%d:%s;\n", i + 1, cities[i]);
}
printf("\n");
}
void printEdges()
{
int nodes = 0;
printf("所有边的信息:\n");
for (int i = 0; i < CITY_NUM; i++)
{
for (int j = i + 1; j < CITY_NUM; j++)
{
if (graph[i][j] != unconnect)
{
printf("节点%d 到 节点%d \n", i + 1, j + 1);
nodes++;
}
}
}
printf("边数:%d", nodes);
printf("\n");
}
void DFS(int node)//递归实现深度遍历
{
S[node] = 1; // 标记节点为已访问
printf("节点%d:%s\n", node + 1, cities[node]);
for (int i = 0; i < CITY_NUM; i++)
{
if (graph[node][i] == connect && S[i] == 0)
{
DFS(i);
}
}
}
void BFS(int startNode)//队列实现广度遍历
{
// 重置S数组
for (int i = 0; i < CITY_NUM; i++)
{
S[i] = 0;
}
int queue[CITY_NUM];
int front = 0, rear = 0;
queue[rear++] = startNode;
S[startNode] = 1; // 标记节点为已访问
while (front < rear)
{
int currentNode = queue[front++];
printf("节点%d:%s\n", currentNode + 1, cities[currentNode]);
for (int i = 0; i < CITY_NUM; i++)
{
if (graph[currentNode][i] == connect && S[i] == 0)
{
queue[rear++] = i;
S[i] = 1; // 标记节点为已访问
}
}
}
}
int isConnectedGraph()
{
int temp=0;
int flag=-1;//返回对应不连通的节点(返回-1表示全连通)
for (int i = 0; i < CITY_NUM; i++)
{
for(int j = 0; j<CITY_NUM; j++){
if (graph[i][j] == unconnect)
{
temp++;
}
}
if(temp > CITY_NUM-1)//若与每个节点的距离均为unconnect则不连通
{
flag = i;
}
temp=0;
}
return flag;
}
int main()
{
int startNode;// 获取用户输入的起始节点
fileop();
printCities();
printEdges();
printf("请输入起始节点编号 (1-%d): ", CITY_NUM);
scanf("%d", &startNode);
if (startNode < 1 || startNode > CITY_NUM)
{
printf("无效的输入。\n");
return 1;
}
startNode=startNode-1; // 数组序号对应节点编号减去1
// 执行深度优先搜索
printf("深度优先搜索结果:\n");
DFS(startNode);
// 执行广度优先搜索
printf("广度优先搜索结果:\n");
BFS(startNode);
if (isConnectedGraph()==-1)
{
printf("是连通图,所有节点都遍历。\n");
}
else
{
printf("不是连通图,节点%d无法遍历。\n",isConnectedGraph()+1);
}
return 0;
}
3.2 文件读取及图的构建
将图形转化为输入数据格式并保存在input1.txt
文件中。完成读取input1.txt
文件,构建图结构
1 2
1 3
1 4
2 3
2 5
3 4
3 5
3 6
4 6
4 7
4 9
5 6
5 8
6 3
6 7
6 8
7 8
7 10
void fileop(void)
{
FILE *fp;
int i, j;
int from, to;
if ((fp = fopen("input1.txt", "r")) == NULL)
{
printf("文件打开失败");
}
else
{
// 初始化图,将每个节点之间权值设为0表示为未连接
for (i = 0; i < CITY_NUM; i++)
{
for (j = 0; j < CITY_NUM; j++)
{
graph[i][j] = unconnect;
}
}
// 读取文件节点之间的权值并赋值
while (fscanf(fp, "%d %d", &from, &to) == 2)
{
graph[from - 1][to - 1] = connect;
graph[to - 1][from - 1] = connect;
}
fclose(fp);
}
}
3.3 打印显示信息
void printCities()
{
printf("节点的编号及名称:\n");
for (int i = 0; i < CITY_NUM; i++)
{
printf("节点%d:%s;\n", i + 1, cities[i]);
}
printf("\n");
}
void printEdges()
{
int nodes = 0;
printf("所有边的信息:\n");
for (int i = 0; i < CITY_NUM; i++)
{
for (int j = i + 1; j < CITY_NUM; j++)
{
if (graph[i][j] != unconnect)
{
printf("节点%d 到 节点%d \n", i + 1, j + 1);
nodes++;
}
}
}
printf("边数:%d", nodes);
printf("\n");
}
3.4深度遍历算法(DFS)和广度遍历算法(BFS)
void DFS(int node)//递归实现深度遍历
{
S[node] = 1; // 标记节点为已访问
printf("节点%d:%s\n", node + 1, cities[node]);
for (int i = 0; i < CITY_NUM; i++)
{
if (graph[node][i] == connect && S[i] == 0)
{
DFS(i);
}
}
}
void BFS(int startNode)//队列实现广度遍历
{
// 重置S数组
for (int i = 0; i < CITY_NUM; i++)
{
S[i] = 0;
}
int queue[CITY_NUM];
int front = 0, rear = 0;
queue[rear++] = startNode;
S[startNode] = 1; // 标记节点为已访问
while (front < rear)
{
int currentNode = queue[front++];
printf("节点%d:%s\n", currentNode + 1, cities[currentNode]);
for (int i = 0; i < CITY_NUM; i++)
{
if (graph[currentNode][i] == connect && S[i] == 0)
{
queue[rear++] = i;
S[i] = 1; // 标记节点为已访问
}
}
}
}
3.5 判断是否为连通图
int isConnectedGraph()
{
int temp=0;
int flag=-1;//返回对应不连通的节点(返回-1表示全连通)
for (int i = 0; i < CITY_NUM; i++)
{
for(int j = 0; j<CITY_NUM; j++){
if (graph[i][j] == unconnect)
{
temp++;
}
}
if(temp>CITY_NUM-1)//若与每个节点的距离均为unconnect则不连通
{
flag = i;
}
temp=0;
}
return flag;
}
3.6 主函数
int main()
{
int startNode;// 获取用户输入的起始节点
fileop();
printCities();
printEdges();
printf("请输入起始节点编号 (1-%d): ", CITY_NUM);
scanf("%d", &startNode);
if (startNode < 1 || startNode > CITY_NUM)
{
printf("无效的输入。\n");
return 1;
}
startNode=startNode-1; // 数组序号对应节点编号减去1
// 执行深度优先搜索
printf("深度优先搜索结果:\n");
DFS(startNode);
// 执行广度优先搜索
printf("广度优先搜索结果:\n");
BFS(startNode);
if (isConnectedGraph()==-1)
{
printf("是连通图,所有节点都遍历。\n");
}
else
{
printf("不是连通图,节点%d无法遍历。\n",isConnectedGraph()+1);
}
return 0;
}
四.调试
五.心得体会
在编写isconnectedGraph()
函数时,代码总是无法实现返回非连通的相应节点,即便确认逻辑没有问题,反复的修改调试也让人心烦意乱,怀疑这么做是否行得通。但往往就是一些微小的错误导致了运行结果的不一致,例如用来记录各个节点是否连通的temp
没有及时清零。所以说,调试代码不光要对自己有信心,更需要细心和扎实的基础。
六.意见
七.附录
结果展示