PTA邻接表存储图的广度优先遍历

目录

邻接表的相关知识

题目分析:

第一步,遍历某个顶点的边表:

第二步,遍历所有顶点的边表(这里用队列来实现)

 第三步,输出起始顶点的值并设置为已经输出过


邻接表的相关知识

首先,让我们来了解一下邻接表的相关知识,熟悉下邻接表这种存储图的数据结构

https://blog.csdn.net/createprogram/article/details/100104235

简单来讲,就是将图中所有顶点存储到一个数组或单链表里,每个顶点本身又作为邻接表(边表)的头节点,边表用于存储当前顶点所有的邻接点,且按大小排序

题目分析:

函数接口定义:

void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) );

其中LGraph是邻接表存储的图,定义如下:

/* 邻接点的定义 */
typedef struct AdjVNode *PtrToAdjVNode; 
struct AdjVNode{
    Vertex AdjV;        /* 邻接点下标 */
    PtrToAdjVNode Next; /* 指向下一个邻接点的指针 */
};
/* 顶点表头结点的定义 */
typedef struct Vnode{
    PtrToAdjVNode FirstEdge; /* 边表头指针 */
} AdjList[MaxVertexNum];     /* AdjList是邻接表类型 */

/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{  
    int Nv;     /* 顶点数 */
    int Ne;     /* 边数   */
    AdjList G;  /* 邻接表 */
};
typedef PtrToGNode LGraph; /* 以邻接表方式存储的图类型 */

函数BFS应从第S个顶点出发对邻接表存储的图Graph进行广度优先搜索,遍历时用裁判定义的函数Visit访问每个顶点。当访问邻接点时,要求按邻接表顺序访问。题目保证S是图中的合法顶点。

裁判测试程序样例:

#include <stdio.h>

typedef enum {false, true} bool;
#define MaxVertexNum 10   /* 最大顶点数设为10 */
typedef int Vertex;       /* 用顶点下标表示顶点,为整型 */

/* 邻接点的定义 */
typedef struct AdjVNode *PtrToAdjVNode; 
struct AdjVNode{
    Vertex AdjV;        /* 邻接点下标 */
    PtrToAdjVNode Next; /* 指向下一个邻接点的指针 */
};

/* 顶点表头结点的定义 */
typedef struct Vnode{
    PtrToAdjVNode FirstEdge; /* 边表头指针 */
} AdjList[MaxVertexNum];     /* AdjList是邻接表类型 */

/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{  
    int Nv;     /* 顶点数 */
    int Ne;     /* 边数   */
    AdjList G;  /* 邻接表 */
};
typedef PtrToGNode LGraph; /* 以邻接表方式存储的图类型 */

bool Visited[MaxVertexNum]; /* 顶点的访问标记 */

LGraph CreateGraph(); /* 创建图并且将Visited初始化为false;裁判实现,细节不表 */

void Visit( Vertex V )
{
    printf(" %d", V);
}

void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) );

int main()
{
    LGraph G;
    Vertex S;

    G = CreateGraph();
    scanf("%d", &S);
    printf("BFS from %d:", S);
    BFS(G, S, Visit);

    return 0;
}

/* 你的代码将被嵌在这里 */

 乍一看,貌似没什么思路,这顶点这么多,对应边表也这么多,这该怎生是好?(滑稽)

别急,一步一步分析,把题目拆开来:

首先,要广度优先遍历,我先实现遍历如何?

第一步,遍历某个顶点的边表:

tmp = Graph->G[i].FirstEdge;//设置一个临时变量来存储当前顶点的第一个邻接点的指针
while (tmp)//判断是否到了某顶点边表末尾
{
	Vertex pos = tmp->AdjV;
	if (!Visited[pos])/*用来设置标记,判断当前节点有没有输出过*/
	{
		Visit(pos);
		Visited[pos] = true;
	}
	tmp = tmp->Next;//依次遍历当前顶点的邻接点
}

第二步,遍历所有顶点的边表(这里用队列来实现)

    int queue[11]; //定义一个数组,存储入队过的顶点
	int l = 0, r = 0;//用来实现队列,即先进先出
    while (l != r) //队列不为空
	{
		tmp = Graph->G[queue[l++]].FirstEdge;//当前顶点出队,边表头结点是当前顶点的边表头结点
		while (tmp)//判断是否到了某顶点边表末尾
		{
			Vertex pos = tmp->AdjV;
			if (!Visited[pos])
			{
				Visit(pos);
				Visited[pos] = true;
				queue[r++] = pos;//将未入队的邻接点入队
			}
			tmp = tmp->Next;//依次遍历当前顶点的邻接点
		}
	}

 第三步,输出起始顶点的值并设置为已经输出过

    int queue[11]; //定义一个数组,存储入队过的顶点
	int l = 0, r = 0;//用来实现队列,即先进先出
	queue[r++] = S;
	Visit(S);
	Visited[S] = true;
	PtrToAdjVNode tmp;
	/*两层循环作用:当前顶点的边表结点即邻接点全部遍历完成后,才遍历下一个顶点*/
	while (l != r) //队列不为空
	{
		tmp = Graph->G[queue[l++]].FirstEdge;//当前顶点出队,边表头结点是当前顶点的边表头结点
		while (tmp)//判断是否到了某顶点边表末尾
		{
			Vertex pos = tmp->AdjV;
			if (!Visited[pos])
			{
				Visit(pos);
				Visited[pos] = true;
				queue[r++] = pos;//将未入队的邻接点入队
			}
			tmp = tmp->Next;//依次遍历当前顶点的邻接点
		}
	}

到这里,第三步所得代码即为所需的BFS函数代码

更加详细的实现:

大佬之作

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 广度优先是一种算法,它从的某个顶点开始遍,先访问该顶点,然后依次访问该顶点的邻接点,再依次访问这些邻接点的邻接点,直到遍完整个。基于邻接矩阵示的广度优先可以通过以下步骤实现: 1. 初始化一个队列,将起始顶点入队。 2. 标记起始顶点为已访问。 3. 从队列中取出一个顶点,访问它的所有未被访问过的邻接点,并将这些邻接点入队。 4. 标记这些邻接点为已访问。 5. 重复步骤3和步骤4,直到队列为空。 在基于邻接矩阵示的中,可以使用一个二维数组来邻接矩阵。数组的第i行第j列示顶点i和顶点j之间是否有边相连。如果有,则为1,否则为。在遍时,可以使用一个一维数组来记录每个顶点是否已经被访问过。初始时,所有顶点的状态都为未访问。 ### 回答2: 广度优先是一种重要的算法,可以对进行系统的搜索和遍。基于邻接矩阵可以方便地实现广度优先,下面我们就来具体讲一讲基于邻接矩阵示的广度优先算法。 首先介绍邻接矩阵的概念。邻接矩阵是用矩阵来示一个无向或有向的数据结构。矩阵中的每个元素代中两个相连顶点之间的边。对于无向邻接矩阵是对称的,对于有向来说则不一定对称。 基于邻接矩阵实现广度优先时,我们需要创建一个队列来存储已访问的节点和还未被访问的节点。首先将起始节点加入队列,并将该节点标记为已访问。接着从队列中取出队首元素,依次访问其所有邻接节点,若邻接节点未被访问,则将其加入队列中,标记为已访问。以此往复,直到队列为空,遍完成。 具体算法实现如下: 1. 初始化一个队列,将起始节点加入队列中,标记为已访问。 2. 当队列不为空时,重复以下步骤: a. 取出队首元素,访问该节点。 b. 遍该节点的所有邻接节点,若未被访问,则加入队列中,标记为已访问。 3. 遍完成后,输出所有遍过的节点。 该算法利用了队列这种数据结构的先进先出的特性,保证了每个节点只被访问一次,最终能够遍中所有节点。 需要注意的是,邻接矩阵示的中,如果两个节点之间没有边,则相应位置的权值为0。在访问节点时,需要特别判断相应位置的权值是否为0,以避免产生误判。 以上就是基于邻接矩阵示的广度优先算法,希望对大家有所帮助。 ### 回答3: 邻接矩阵是一种常用的示方法,广度优先是一种常见的搜索算法。在使用邻接矩阵时,广度优先的实现过程如下: 1. 从中的任意一个顶点开始进行遍。 2. 将该顶点标记为已访问,并将其加入队列中。 3. 从队列中取出一个顶点,访问其未被访问过的邻居顶点,并将它们标记为已访问,并将它们加入队列中。 4. 重复步骤3,直到队列为空。 具体地说,可以通过二维数组来实现邻接矩阵。假设中有n个顶点,则使用一个n*n的矩阵来示。如果矩阵中的元素a[i][j]为1,则示顶点i和j之间有一条边;如果为0,则示没有边。在广度优先中,需要使用一个队列来记录遍的顺序。同时还需要标记每个顶点是否被访问过,在实现过程中可以使用一个布尔数组来记录。 下面是一个基于邻接矩阵示的广度优先算法的伪代码: 1. 创建一个队列,将起始顶点v加入队列中,同时将v标记为已访问 2. 当队列不为空时,重复执行以下步骤: a. 从队列头部取出一个顶点u b. 访问顶点u c. 遍邻接矩阵中与顶点u相邻的顶点,如果该顶点未被访问过,则将其加入队列中,并标记为已访问 3. 遍完成后,所有顶点都被访问过。 其中,步骤2c涉及到遍邻接矩阵中与顶点u相邻的顶点,可以通过遍一行或一列来实现。对于矩阵中第i行的元素,如果a[i][j]为1,则示顶点i和j之间有一条边,此时可以将j加入队列中。 综上所述,基于邻接矩阵示的广度优先算法比较直观且易于实现,但是需要开辟一个二维数组来存储邻接矩阵,空间复杂度相对较高。同时,在某些情况下,邻接矩阵的示方式可能并不太适合,比如当中边的数目较少时,使用邻接示方式可能更加高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值