无向图中基于宽度优先搜索的求两个节点间的最短跳数

一、问题描述   

    跳数是网络路由中的术语,表示消息从一个路由器传送到另一个路由器要经过几个节点的转发,就称为几跳。那么有一个问题就是,当需要找到转发次数最短的路径时,就会涉及到从一个节点到另一个节点之间最短跳数问题。


                                        图1 一个简单的无向图

    如在图1中所示,从节点0到节点6的跳数为2,我们通过肉眼可以很快的分辨,然而当图中的节点数变多,路径连接更加复杂时,肉眼就无法观察出结果了。

二、方法介绍

    在图中有一种遍历图的方式叫宽度优先搜索(BFS),可以被用到该问题的求解中来。我们可以从起始节点开始进行宽度优先遍历,当遍历到所要求解的那个节点时,遍历的深度即为这两个节点间的最短跳数。在宽度优先搜索中,通常需要采用队列的方式来完成,首先将遍历到的节点压入队列,然后依次从队列中取出队首节点,寻找该节点的相邻节点,再次压入队列,直到找到所求节点或则队列元素为空即停止遍历。

     因此解决该文题的关键是宽度优先搜索方法的实现和队列的构建。

三、程序实现

     为了程序实现上述问题的求解,并提供结果演示。首先通过将图1所示的无向图转换为数据的方式存储在文本文件中。文本文件命名为data.txt, 在该文件中首先存储的一行数据包含两个元素,依次为图所包含的节点总数n,图中边的总数edge,数据之间用空格分开,结尾通过回车换行。接下来为edge行数据,每一行有三个数据,依次为边的起始节点,边的结束节点,边的权重,数据之间用空格分开,每一行结尾采用回车换行。如图1所示的无向图转化为数据存储在data.txt中后如图2所示:


                                                                                               图2 无向图数据

      数据读取出后,采用邻接矩阵存储。在所编写的程序中通过函数int routeHop(int **a, int n, int s, int d)来求解两个节点之间的最短跳数,a为无向图的邻接矩阵,n为图中节点综述,s为起点,d为终点。该函数的返回值为s点到d的最短跳数。该函数的基本实现思路为:首先构建一个队列,然后构建一个长度为n的标志位数组。初始化s点的标志位为0,其他节点的标志位为-1,接着寻找s点相邻的节点且为未访问的节点,将其标志为置为s点的标志位加1,然后将该节点入栈,后续过程重复该搜索过程。最终找到d节点是结束,d节点的标志位数值代表的就是从s点到d点的最短跳数。

以下是程序运行的结果:


                                             图3 程序运行结果1


                                              图4 程序运行结果2

四、程序源代码

#include "stdio.h"
#include<stdlib.h>


#define ok 0  //函数运行正常返回值
#define error 1  //函数运行发生异常返回值
#define maxOfInt 999999  //定义的最大整数值,用来表示两个节点之间没有路径


int read_data(int ***a,int *n);
int routeHop(int **a, int n, int s, int d);


int main()
{
int **D, n,i = 0, j = 0;
read_data(&D, &n); //读取图的信息
i = 0;
j = 9;
printf("%d ---> %d 为 %d跳\n", i, j, routeHop(D, n, i, j));
return ok;
}
int read_data(int ***a,int *n)
{
FILE * fp;
int i = 0,j = 0, x = 0, y = 0, edge = 0;
if( (fp  = fopen( "data.txt", "r" )) == NULL )  //##############修改此处的data.txt参数为data2.txt可以更换测试用例###############
{
printf( "The file 'data.txt' was not opened\n" );
return error;
}
else
{
fscanf(fp,"%d %d\n",&(*n), &edge);
//此处没有判断数据输入的合法性,默认输入的数据合法

(*a)=(int **)malloc((*n)*sizeof(int*));
for(i = 0;i < *n; ++i)  //初始化图邻接矩阵
{
(*a)[i] = (int*)malloc((*n) * sizeof(int));
for (j = 0; j < *n; ++j)
{
if (i == j)
(*a)[i][j] = 0;
else
(*a)[i][j] = maxOfInt;
}
}
for(i = 0;i < edge; ++i)  //读取路径信息
{
x = y = j =0;
fscanf(fp,"%d %d %d",&x, &y, &j);
(*a)[x][y] = j;
(*a)[y][x] = j;
}
if( fclose( fp ) )
printf( "The file 'data.txt' was not closed\n" );
return ok;
}
}


int routeHop(int **a, int n, int s, int d) //返回从s到d最少经过的房间数,即跳数,采用的是宽度优先搜索(BFS)的方法,构建了一个队列来辅助实现
{
int *que, *Visited, head, rear, i, j;
que = (int *)malloc(n * sizeof(int));
head = rear = 0;
Visited = (int *)malloc(n * sizeof(int));
for (i = 0; i < n; ++i)
Visited[i] = 0;
Visited[s] = 1;
que[rear++] = s;
while (Visited[d] == 0 && head != rear)
{
i = que[head++];
for (j = 0; j < n; ++j)
{
if (i != j && Visited[j] == 0 && a[i][j] < maxOfInt)
{
Visited[j] = Visited[i] +1;
que[rear++] = j;
}
}
}
j = Visited[d] - 1;
free(que);
if (Visited[d] == 0)
{
free(Visited);
return maxOfInt;
}
else
{
free(Visited);
return j;
}
}

展开阅读全文

没有更多推荐了,返回首页