6-1 邻接表存储图的广度优先遍历

11 篇文章 0 订阅
10 篇文章 1 订阅

6-1 邻接表存储图的广度优先遍历

分数 20

全屏浏览题目

切换布局

作者 DS课程组

单位 浙江大学

试实现邻接表存储图的广度优先遍历。

函数接口定义:

 

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;
}

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

输入样例:给定图如下

2

输出样例:

BFS from 2: 2 0 3 5 4 1 6

 我的第一种方法(错):

#include <stdio.h>
#include <stdlib.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 struct {
	int L,R;
} bian;

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();
	for(int i=0; i<7; i++) {
		PtrToAdjVNode k;
		printf("%d:",i);
		k=G->G[i].FirstEdge;
		if(k) {
			while(k) {
				printf(" %d",k->AdjV);
				k=k->Next;
			}
		}
		printf("\n");
	}
	printf("请输入要开始进行遍历的结点:");
	scanf("%d", &S);
	printf("BFS from %d:", S);
	BFS(G, S, Visit);

	return 0;
}

/* 你的代码将被嵌在这里 */
//实现遍历-》广度遍历
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) ) {we
	int list[1000];
	int left,right;
	left=right=0;
	Visit(S);
	Visited[S]=true;
	PtrToAdjVNode i;
//	注意G并不是指针,是一个数组类型的,即像int a.
	i=Graph->G[S].FirstEdge;
	int x;
	while(i) {
		Visited[i->AdjV]=true;
		list[right++]=i->AdjV;
		i=i->Next;
	}
	while(left<right) {
//		printf("left:%d,right:%d\n",left,right);
		int tran=list[left++];
		Visit(tran);//出队
		//Visited[tran]=true;
		for(PtrToAdjVNode w=Graph->G[tran].FirstEdge; w; w=w->Next) {
			if(!Visited[w->AdjV]) {
//				放入队列的时要先进行标记表示已经访问过了
				Visited[w->AdjV]=true;
				list[right++]=w->AdjV;
			}
		}
	}
}


LGraph CreateGraph() {
	LGraph head;
	bian *tran;
	PtrToAdjVNode lin;
	tran=(bian *)malloc(sizeof(bian));
	head=(LGraph)malloc(sizeof(struct GNode));

	//注意顶点的存储从0开始存储
	printf("总的顶点数:");
	scanf("%d",&head->Nv);
	//	初始化
	for(int i=0; i<MaxVertexNum; i++) {
		head->G[i].FirstEdge=NULL;
	}

	printf("请输入边的个数:");
	scanf("%d",&head->Ne);
//	存储开始
	for(int i=0; i<head->Ne; i++) {
		printf("请输入两个顶点:");
		scanf("%d%d",&tran->L,&tran->R);
		lin=(PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
//		第一次(无向图)
		lin->AdjV=tran->R;
		lin->Next=head->G[tran->L].FirstEdge;
		head->G[tran->L].FirstEdge=lin;
		printf("%d %d\n",tran->L,head->G[tran->L].FirstEdge->AdjV);
//		返回来存
//注意又得申请一组空间,不然进行的操作都在同一组空间中
		lin=(PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
		lin->AdjV=tran->L;
		lin->Next=head->G[tran->R].FirstEdge;
		head->G[tran->R].FirstEdge=lin;
		printf("%d %d\n",tran->R,head->G[tran->R].FirstEdge->AdjV);
	}
	return head;
}

改正+总结思路:

//无论是用什么方式存储图,data域我们一般表示存储的是该节点的名字
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) ) {
//	创建队列进行存储入队结点的名字
	int list[1000];
	int pre,left;
	PtrToAdjVNode tran;
	pre=left=0;
	Visited[S]=true;//进入队列的就是已经访问过了,要进行标记
	list[pre++]=S;
	while(left<pre) {
		int i=list[left++];//表示出对,取出出队的结点
		Visit(i);
//		Visited[i]=true;在入队的时候就已经进行标记了 
		tran=Graph->G[i].FirstEdge;//获取该结点名字在表头的位置的相邻结点 ,注意这里一定是i,不是S,
		//如果是S就获得不了 在队列的下一个结点,就只会在S的这个位置不变。 
		//将该节点的相邻结点进行入对
		while(tran){
			if(!Visited[tran->AdjV]){//除了要进行检测有没有相邻的结点,还要进行检测有没有访问过该节点 
				//没有访问就进行入队,同是进行标记
				 Visited[tran->AdjV]=true;
				 list[pre++]=tran->AdjV;
			}
			tran=tran->Next;//这个不能写在if里面,不然tran的位置在不执行if时就会不动 
		}
	}
}
//创建
LGraph CreateGraph() {
	LGraph head;
	bian *tran;
	PtrToAdjVNode lin;
	tran=(bian *)malloc(sizeof(bian));
	head=(LGraph)malloc(sizeof(struct GNode));
 
	//注意顶点的存储从0开始存储
	printf("总的顶点数:");
	scanf("%d",&head->Nv);
	//	初始化
	for(int i=0; i<MaxVertexNum; i++) {
		head->G[i].FirstEdge=NULL;
	}
 
	printf("请输入边的个数:");
	scanf("%d",&head->Ne);
//	存储开始
	for(int i=0; i<head->Ne; i++) {
		printf("请输入两个顶点:");
		scanf("%d%d",&tran->L,&tran->R);
		lin=(PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
//		第一次(无向图)
		lin->AdjV=tran->R;
		lin->Next=head->G[tran->L].FirstEdge;
		head->G[tran->L].FirstEdge=lin;
		printf("%d %d\n",tran->L,head->G[tran->L].FirstEdge->AdjV);
//		返回来存
//注意又得申请一组空间,不然进行的操作都在同一组空间中
		lin=(PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
		lin->AdjV=tran->L;
		lin->Next=head->G[tran->R].FirstEdge;
		head->G[tran->R].FirstEdge=lin;
		printf("%d %d\n",tran->R,head->G[tran->R].FirstEdge->AdjV);
	}
	return head;
}

总结:采用第一种方法不能说有错,我问老师后,老师说可能是是这个pta的程序设置有问题,因为两种方法的思路是一样的,只不过我的第一种是将第二种的开始位置入队放在前面而已。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小丞啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值