图的建立(邻接矩阵)与其深度优先和广度优先遍历

建立一个有向图或无向图,输入其顶点数,边数,并给出相应边的权值,输出该图对应的邻接矩阵,并用递归实现其深度优先遍历和用队列实现其广度优先遍历后的结果.

图的遍历 

从给定图中任意指定的顶点(称为初始点)出发,按照某种搜索方法沿着图的边访问图中所有顶点,使每个顶点仅被访问一次,这个过程称为图的遍历
图的遍历方法有两种,一种叫深度优先遍历(DFS,另一种叫广度优先遍历(BFS).

图的邻接矩阵表示

通常图的表示有两种方法:邻接矩阵,邻接表

本文用邻接矩阵实现,一是代码量更少,二是代码风格也更贴近C语言。但不论是图的哪种实现方式,其基本的实现思想是不变的。

1:节点的信息,我们用一维数组a[n]来存储,假设图共有n个节点。

2:节点与节点间的关系,我们用二维数组b[n][n]存储。

3:b[i][j]表示,从i到j有向连通,b[j][i]表示从j到i有向连通,而当i=j时(矩阵的对角线上的元素),b[i][j]没有实际意思,在遍历时,我可以用来存储定节点是否访问过。

深度优先遍历(DFS)

图的深度优先搜索(Depth First Search),和树的先序遍历比较类似。

它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到。 若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

显然,深度优先搜索是一个递归的过程

深度优先遍历特点是,选定一个出发点后进行遍历,能前进则前进,若不能前进,回退一步再前进,或再回退一步后继续前进。依此重复,直到所有与选定点相通的所有顶点都被遍历。

广度优先遍历(BFS)​​​​​​​
广度优先遍历的过程是首先访问初始点v,接着访问顶点v的所有未被访问过的邻接点v1,v2,…,vt,然后再按照v1,v2,…,vt的次序访问每一个顶点的所有未被访问过的邻接点,以此类推,直到图中所有和初始点v有路径相通的顶点都被访问过为止。
在遍历以邻接表为存储结构的图时,需要使用一个队列,

#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 100   //最大定点顶点数 
#define INFINITF 65535  //用 65535来表示无穷 
#define	MAX 100
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0 
#define OK 1 
#define ERROR 0
typedef int Boolean;	//Boolean是布尔类型,其值是TRUE或FALSE
Boolean visited[MAX];
typedef struct{
	char vexs[MAXVEX];  //顶点表 
	int arc[MAXVEX][MAXVEX];  //邻接矩阵,可看作边表
	int numVertexes,numEdges;  //图中当前的顶点数 
	int GraphType; //图的类型 
}MGraph;
typedef struct{
	int data[MAXSIZE];
	int front;     //头指针 
	int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置 
}SqQueue;
//初始化一个空队列
int InitQueue(SqQueue *Q)
{
	Q->front=0;
	Q->rear=0;
	return OK;
}
int QueueEmpty(SqQueue Q)
{
	if(Q.rear==Q.front)
		return TRUE;
	else
		return FALSE;
}
//循环队列入队列操作 
int EnQueue(SqQueue *Q,int e) 
{
	if ((Q->rear+1)%MAXSIZE == Q->front);  //队列满的判断
		return ERROR;
	Q->data[Q->rear]=e;  //将元素e赋值给队尾
	Q->rear=(Q->rear+1)%MAXSIZE; //rear指针向后移一位置,若到最后则转到数组头部
	return OK; 

}
// 循环队列出队列操作
int DeQueue(SqQueue *Q,int *e)
{
	if (Q->front == Q->rear)
		return ERROR; //队列空的判断
	*e = Q->data[Q->front];  //将队头元素赋值给e 
	Q->front=(Q->front+1)%MAXSIZE; //front指针向后移一位置
	return OK; 
} 
void CreateMGraph (MGraph *G)
{
	int i,j,k,w;
	printf("输入顶点数和边数:\n");
	scanf("%d %d",&G->numVertexes,&G->numEdges); //输入顶点数和边数
	fflush(stdin);
	for(i=0;i<G->numVertexes;i++)
	{
		printf("第%d个顶点",i+1);
		scanf("%c",&G->vexs[i]);
		getchar (); 
	}
	for(i=0;i<G->numVertexes;i++)
		for(j=0;j<G->numVertexes;j++)
			G->arc[i][j]=INFINITF ; //邻接矩阵初始化 
	for(k=0;k<G->numEdges;k++)
	{
		printf("输入边(vi,vj)上的上标i,下标j和权W:");
		scanf("%d %d %d",&i,&j,&w); //输入边(vi,vj)上的权W
		G->arc[i][j]=w;
		if(G->GraphType==0)
		G->arc[j][i]=G->arc[i][j];  //因为是无向图,矩阵对称 
	}
}
  //输出邻接矩阵
void output(MGraph *G) 
{
	int i,j,count=0;
	for (i=0;i<G->numVertexes;i++)
		printf("\t%c",G->vexs[i]);	
	printf("\n");
	for(i=0;i<G->numVertexes;i++)
	{
		printf("%4c",G->vexs[i]);
		for(j=0;j<G->numVertexes;j++)
		{
			printf("\t%d",G->arc[i][j]);
			count++;
			if(count%G->numVertexes==0)
			printf("\n");
		}
	}
}
//邻接矩阵的深度优先递归算法 
void DFS (MGraph G,int i)
{
	int j;
	visited[i]=TRUE;
	printf("%c ",G.vexs[i]);  //打印顶点
	for(j=0;j<G.numVertexes;j++)
	{
		if(G.arc[i][j]==1&&!visited[j])
		DFS(G,j);  //对未访问的邻接顶点递归调用 
	}	 
} 
//邻接矩阵的深度遍历操作
void DFSTraverse(MGraph G)
{
	int i;
	for(i=0;i<G.numVertexes;i++)
		visited[i]=FALSE;  //初始化所有顶点状态都是未访问过状态 
	for(i=0;i<G.numVertexes;i++)
		if(!visited[i])   //对未访问过的顶点调用DFS,若是连通图,只会执行一次 
		DFS(G,i); 
} 
void BFSTraverse(MGraph G)
{
	int i,j;
	SqQueue Q;
	for(i=0;i<G.numVertexes;i++)
		visited[i]=FALSE;
	InitQueue(&Q);  //初始化一辅助用的队列
	for(i=0;i<G.numVertexes;i++)  //对每个顶点做循环 
	{
		if(!visited[i])  //若是未访问过就处理 
		{
			visited[i]=TRUE;  //设置当前顶点访问过 
			printf("%c ",G.vexs[i]);  //打印顶点
			EnQueue(&Q,i);	 //将此顶点入队列 
			while(!QueueEmpty(Q)) //若当前队列不为空 
			{
				DeQueue(&Q,&i); //将队中元素出队列,赋值给i 
				for(j=0;j<G.numVertexes;j++)
				{
					//判断其他结点若与当前顶点存在且未访问过 
					if(G.arc[i][j] == 1&& !visited[j])
					{
						visited[j]=TRUE;  //将找到的此顶点标记为已访问 
						printf("%c ",G.vexs[j]);  //打印顶点 
						EnQueue(&Q,j); //将找到的此顶点入队列 
					}
				}
			} 
		} 
	} 
}
int main()
{
	MGraph G;
	int i,j;
	printf("输入图的类型(无向图0/有向图1):");
	scanf("%d",&G.GraphType); 
	CreateMGraph (&G);
	printf("邻接矩阵数据如下:\n");
	output(&G); 
	printf("\n");
	printf("图的深度优先遍历如下:\n");
	DFSTraverse(G);
	printf("\n图的广度优先遍历如下:\n");
	BFSTraverse(G);
	return 0;
}
 

  • 19
    点赞
  • 120
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
邻接矩阵是一种的存储结构,它可以用来表示有限个顶点之间的关系。邻接矩阵深度优先遍历广度优先遍历的两种基本遍历方式。 邻接矩阵深度优先遍历(Depth First Search,DFS): 深度优先遍历是一种用于遍历或搜索树或的算法。在这个算法中,首先访问根节点,然后递归地访问每个子节点。当访问一个节点时,将其标记为已访问,以避免重复访问。深度优先遍历使用栈来实现,因此它是一种先进后出(Last In First Out,LIFO)的算法。 下面是邻接矩阵深度优先遍历的Python代码示例: ```python def DFS(graph, start): visited = set() # 用集合来存储已经访问过的节点 stack = [start] # 用列表来模拟栈 while stack: vertex = stack.pop() # 取出栈顶元素 if vertex not in visited: visited.add(vertex) # 标记为已访问 print(vertex, end=' ') # 将未访问的邻居节点入栈 stack.extend([i for i in range(len(graph[vertex])) if graph[vertex][i] and i not in visited]) # 示例 graph = [[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]] DFS(graph, 0) # 输出:0 1 3 2 ``` 邻接矩阵广度优先遍历(Breadth First Search,BFS): 广度优先遍历是一种用于遍历或搜索树或的算法。在这个算法中,首先访问根节点,然后逐层访问每个子节点。当访问一个节点时,将其标记为已访问,以避免重复访问。广度优先遍历使用队列来实现,因此它是一种先进先出(First In First Out,FIFO)的算法。 下面是邻接矩阵广度优先遍历的Python代码示例: ```python from collections import deque def BFS(graph, start): visited = set() # 用集合来存储已经访问过的节点 queue = deque([start]) # 用双端队列来模拟队列 while queue: vertex = queue.popleft() # 取出队首元素 if vertex not in visited: visited.add(vertex) # 标记为已访问 print(vertex, end=' ') # 将未访问的邻居节点入队 queue.extend([i for i in range(len(graph[vertex])) if graph[vertex][i] and i not in visited]) # 示例 graph = [[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]] BFS(graph, 0) # 输出:0 1 2 3 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一团糟~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值