广度优先搜索(邻接矩阵)

广度优先搜索(邻接矩阵)

在这里插入图片描述

1.1一、用数组来存放顶点

vexs[0] = ‘A’
vexs[1] = ‘B’
vexs[2] = ‘C’
vexs[3] = ‘D’
vexs[4] = ‘E’
vexs[5] = ‘F’
vexs[6] = ‘G’
vexs[7] = ‘H’
vexs[8] = ‘I’

1.2、用邻接矩阵来表示边

在这里插入图片描述

上面这个矩阵中,0表示每个顶点没有到达自己的路径。1表示两个顶点之间有路径,无穷大表示两个顶点之间没有路径。
假如按照程序计数习惯,行或列都从0数起。
第0行第0列为0,表示A到它本身之间没有路径(这是人为规定的,因为A到它自身不需要路径)。
第0行第1列为1,表示顶点A和B之间有路径。
第0行第5列为1,表示顶点A和顶点F之间有路径。
第0行其他列为无穷大,表示A到其它点之间没有路径。
……
因为是无向图,邻接矩阵必然有两个特点:
① 对角线(左上角到右下角)上的元素值全为0.表示每个点到它自身没有(或不需要)路径。
② 其它的元素关于对角线对称。
如果不同的顶点之间没有路径,也是用0来表示,则邻接矩阵为
在这里插入图片描述

上面的邻接矩阵,在编程时可以用二维数组来实现:
arc[0][1] = arc[1][0] = 1;
arc[0][5] = arc[5][0] = 1;

arc[1][2] = arc[2][1] = 1;
arc[1][6] = arc[6][1] = 1;
arc[1][8] = arc[8][1] = 1;

arc[2][3] = arc[3][2] = 1;
arc[2][8] = arc[8][2] = 1;

arc[3][4] = arc[4][3] = 1;
arc[3][6] = arc[6][3] = 1;
arc[3][7] = arc[7][3] = 1;
arc[3][8] = arc[8][3] = 1;

arc[4][5] = arc[5][4] = 1;
arc[4][7] = arc[7][4] = 1;

arc[5][6] = arc[6][5] = 1;

arc[6][7] = arc[7][6] = 1;

1.3 广度优先遍历

广度优先遍历需要借助于另外的数据结构队列。当把图中的顶点放到队列中时,表示这个顶点被遍历了(可以把顶点的值打印出来)。
用图1中的右图来分析广度优先遍历更方便,因为右图的层次结构更明显。

在这里插入图片描述

起初,把点A放入队列中,A被遍历。如上图中的(1)所示。
接着把队首元素A出队,把A的下一层的顶点B和F移进队列,B和F被遍历。如上图中的(2)所示。
队首元素B出队,B的下一层顶点C,G,I相继入队,C、G和I被遍历。如上图中的(3)所示。
队首元素F出队,F的下一层顶点E入队,E被遍历。如上图中的(5)所示。
队首元素C出队,C的下一层顶点D入队,D被遍历。如上图中的(6)所示。
队首元素G出队,G的下一层有两个顶点:D和H。D已在队列里,H入队,H被遍历。如上图中的(4)所示。
队首元素I出队,I的下一层顶点D已在队列里,没有新顶点入队。如上图中的(7)所示。
队首元素E出队,E的下一层顶点D和H都已在队列里,没有新顶点入队。如上图中的(8)所示。
队首元素D出队,D没有下一层顶点,所以没有新顶点入队。如上图中的(9)所示。
队首元素H出队,H没有下一层顶点,所以没有新顶点入队。此时队列为空,遍历结束。
最终,广度优先遍历的顺序即入队列(或出队列)的顺序:A B F C G I E D H

2.1 邻接矩阵生成
#define MAX_VEX_NUM 20 
typedef char VertextType;
typedef enum { DG, UDG }GraphKind; //判定图的类型,有向或无向
typedef struct
{
	VertextType vexs[MAX_VEX_NUM]; //存放结点的char行数组
	int arcs[MAX_VEX_NUM][MAX_VEX_NUM]; //存放边的数组
	int vexnum, arcnum;//结点数,边数
	GraphKind Type;//存放图的类型
}MGraph;

//索引判断
int index(char vex, MGraph* mg)
{
	int i;
	for (i = 1;i <= mg->vexnum;i++)
	{
		if (mg->vexs[i] == vex)
			return i;
	}
	return 0;

}

//生成邻接矩阵
void Creat_MG(MGraph* mg)
{
	int type, i, j, k, v1_index, v2_index;
	char v1, v2;
	printf("please input graph type 0.DG 1.UDG. input nums:");
	scanf_s("%d", &type);  //输入图的类型
	if (type == 0)
		mg->Type = DG;
	else if (type == 1)
	{
		mg->Type = UDG;
	}
	else
	{
		printf("please input 0 or 1!!!");
		return;
	}
	printf("Please input vexnum:");
	scanf_s("%d", &mg->vexnum); //输入结点数
	printf("Please input arcnum:");
	scanf_s("%d", &mg->arcnum);//输入边数
	getchar();
	for (i = 1;i <= mg->vexnum;i++)
	{
		printf("please input %d vex:", i);
		scanf_s("%c", &mg->vexs[i],1);//循环存放每个结点
		getchar();
	}
	for (i = 1;i <= mg->vexnum;i++)
		for (j = 1;j <= mg->vexnum;j++)
			mg->arcs[i][j] = 0;//初始化边,全部设为0
	for (k = 1;k <= mg->arcnum;k++)
	{
		printf("Please input %d arc(vex1,vex2):", k);
		scanf_s("%c %c", &v1,1, &v2,1);
		v1_index = index(v1, mg);//索引该结点对应的位置
		v2_index = index(v2, mg);//索引该结点对应的位置
		if (mg->Type == 1)//如果是无向图
		{
			mg->arcs[v1_index][v2_index] = 1;
			mg->arcs[v2_index][v1_index] = 1;//将矩阵的对应的值1
		}
		else
			mg->arcs[v1_index][v2_index] = 1;
		getchar();
	}
}

void Print_MG(MGraph* mg)
{
	int i, j;
	if (mg->Type == 0)
		printf("Is Direct Graph\n");
	else
		printf("Is UNDirect Graph\n");
	for (i = 1;i <= mg->vexnum;i++)
	{
		for (j = 1;j <= mg->vexnum;j++)
		{
			printf("%d  ", mg->arcs[i][j]);//遍历输出矩阵
		}
		printf("\n");
	}
}

2.1创建队列
#define M 50

//循环队列的结构类型定义
typedef int DataType;
typedef struct
{
	DataType sequ[M];
	int  rear, quelen;
}Queue;


//建立队
Queue* creatQueue()
{
	Queue* sq;
	sq = (Queue*)malloc(sizeof(Queue));
	return sq;
}
//置空队
void InitQueue(Queue* sq)
{
	sq->rear = M - 1;
	sq->quelen = 0;
}
//入队
void QueueIn(Queue* sq, DataType x)
{
	if (sq->quelen == 50)
		printf("Errot! The queue will be overflow! \n");
	else if ((sq->rear + 1) == M)
	{
		sq->rear = (sq->rear + 1) % M;
		sq->sequ[sq->rear] = x;
		sq->quelen++; 
	}
	else
	{
		sq->rear++;
		sq->sequ[sq->rear] = x;
		sq->quelen++;
	}
}

//出队
DataType QueueOut(Queue* sq)
{
	DataType sun = 0;
	if (sq->quelen == 0)
	{
		printf("Error! The queue will be under flow!\n");
		return 0;
	}
	else if ((sq->rear + 1) >= sq->quelen)
	{
		sq->quelen--;
		sun = sq->sequ[sq->rear - sq->quelen];
		return(sun);
	}
	else    
	{
		sq->quelen--;
		sun = sq->sequ[sq->rear - sq->quelen + M];
		return(sun);
	}
}

//判断队列是否为空
int Empty(Queue* sq)
{
	if (sq->quelen == 0)

	{
		printf("Error! The queue will be under flow!\n");
		return 0;
	}
	return 1;
}

2.3 BFS算法
//BFS算法实现思路1
void BFsTraverse(MGraph G)
{
	int i, j , v = 0;
	Queue *Q = creatQueue();
	InitQueue(Q);
	int visited[100];
	for ( i = 0; i <= G.vexnum; i++)
	{
		visited[i] = 0;
	}
	for ( i = 1; i <= G.vexnum; i++)
	{
		if (!visited[i])
		{
			printf("%c", G.vexs[i]);
			visited[i] = 1;
			//返问过入队
			QueueIn(Q , i);

			while (!Q)
			{
				//出队
				v = QueueOut(Q);
				//出队的同时将该节点的邻接边(弧)入队
				for (j = 1; j <= G.vexnum; j++)
				{
					if (G.arcs[i][j] == 1 && visited[j] != 1)
					{
						printf("%c", G.vexs[j]);
						visited[j] = 1;
						QueueIn(Q, j);
					}
				}
			}
		}

	}

}

//BFS算法实现思路2
int visited[100] = {0};
void BFS(MGraph G, int v0)    //vo搜索起点
{
	int i, j, v = 0;
	Queue* Q = creatQueue();
	InitQueue(Q);
	//起点入队 
	if (!visited[v0])
	{
		QueueIn(Q, v0);
		visited[v0] = 1;
		printf("%c", G.vexs[v0]);
		while (!Empty(Q))
		{
			v = QueueOut(Q);
			for (j = 1;j <= G.vexnum; j++)
			{
				if (G.arcs[v][j] == 1 && visited[j] != 1)
				{
					printf("%c", G.vexs[j]);
					visited[j] = 1;
					QueueIn(Q, j);
				}
			}
		}
	}
		
	//搜索其他树,防止森林其他树为搜索
	for (i = 1; i <= G.vexnum; i++)
	{
		if (visited[i] != 1 )
		{
	                      BFS(G, i);
		}
	}
}

完整代码


#include<stdio.h>
#include<stdlib.h>
#define MAX_VEX_NUM 20    //最大顶点数

#define M 50   //队列长度
typedef char VertextType;
typedef enum { DG, UDG }GraphKind; //判定图的类型,有向或无向
typedef struct
{
	VertextType vexs[MAX_VEX_NUM]; //存放结点的char行数组
	int arcs[MAX_VEX_NUM][MAX_VEX_NUM]; //存放边的数组
	int vexnum, arcnum;//结点数,边数
	GraphKind Type;//存放图的类型
}MGraph;




//循环队列的结构类型定义
typedef int DataType;
typedef struct
{
	DataType sequ[M];
	int  rear, quelen;
}Queue;


//建立队
Queue* creatQueue()
{
	Queue* sq;
	sq = (Queue*)malloc(sizeof(Queue));
	return sq;
}
//置空队
void InitQueue(Queue* sq)
{
	sq->rear = M - 1;
	sq->quelen = 0;
}
//入队
void QueueIn(Queue* sq, DataType x)
{
	if (sq->quelen == 50)
		printf("Errot! The queue will be overflow! \n");
	else if ((sq->rear + 1) == M)
	{
		sq->rear = (sq->rear + 1) % M;
		sq->sequ[sq->rear] = x;
		sq->quelen++; 
	}
	else
	{
		sq->rear++;
		sq->sequ[sq->rear] = x;
		sq->quelen++;
	}
}

//出队
DataType QueueOut(Queue* sq)
{
	DataType sun = 0;
	if (sq->quelen == 0)
	{
		printf("Error! The queue will be under flow!\n");
		return 0;
	}
	else if ((sq->rear + 1) >= sq->quelen)
	{
		sq->quelen--;
		sun = sq->sequ[sq->rear - sq->quelen];
		return(sun);
	}
	else    
	{
		sq->quelen--;
		sun = sq->sequ[sq->rear - sq->quelen + M];
		return(sun);
	}
}

//判断队列是否为空
int Empty(Queue* sq)
{
	if (sq->quelen == 0)

	{
		printf("Error! The queue will be under flow!\n");
		return 0;
	}
	return 1;
}

//索引判断
int index(char vex, MGraph* mg)
{
	int i;
	for (i = 1;i <= mg->vexnum;i++)
	{
		if (mg->vexs[i] == vex)
			return i;
	}
	return 0;

}

//生成邻接矩阵
void Creat_MG(MGraph* mg)
{
	int type, i, j, k, v1_index, v2_index;
	char v1, v2;
	printf("please input graph type 0.DG 1.UDG. input nums:");
	scanf_s("%d", &type);  //输入图的类型
	if (type == 0)
		mg->Type = DG;
	else if (type == 1)
	{
		mg->Type = UDG;
	}
	else
	{
		printf("please input 0 or 1!!!");
		return;
	}
	printf("Please input vexnum:");
	scanf_s("%d", &mg->vexnum); //输入结点数
	printf("Please input arcnum:");
	scanf_s("%d", &mg->arcnum);//输入边数
	getchar();
	for (i = 1;i <= mg->vexnum;i++)
	{
		printf("please input %d vex:", i);
		scanf_s("%c", &mg->vexs[i],1);//循环存放每个结点
		getchar();
	}
	for (i = 1;i <= mg->vexnum;i++)
		for (j = 1;j <= mg->vexnum;j++)
			mg->arcs[i][j] = 0;//初始化边,全部设为0
	for (k = 1;k <= mg->arcnum;k++)
	{
		printf("Please input %d arc(vex1,vex2):", k);
		scanf_s("%c %c", &v1,1, &v2,1);
		v1_index = index(v1, mg);//索引该结点对应的位置
		v2_index = index(v2, mg);//索引该结点对应的位置
		if (mg->Type == 1)//如果是无向图
		{
			mg->arcs[v1_index][v2_index] = 1;
			mg->arcs[v2_index][v1_index] = 1;//将矩阵的对应的值1
		}
		else
			mg->arcs[v1_index][v2_index] = 1;
		getchar();
	}
}

//BFS算法实现思路1
void BFsTraverse(MGraph G)
{
	int i, j , v = 0;
	Queue *Q = creatQueue();
	InitQueue(Q);
	int visited[100];
	for ( i = 0; i <= G.vexnum; i++)
	{
		visited[i] = 0;
	}
	for ( i = 1; i <= G.vexnum; i++)
	{
		if (!visited[i])
		{
			printf("%c", G.vexs[i]);
			visited[i] = 1;
			//返问过入队
			QueueIn(Q , i);

			while (!Q)
			{
				//出队
				v = QueueOut(Q);
				//出队的同时将该节点的邻接边(弧)入队
				for (j = 1; j <= G.vexnum; j++)
				{
					if (G.arcs[i][j] == 1 && visited[j] != 1)
					{
						printf("%c", G.vexs[j]);
						visited[j] = 1;
						QueueIn(Q, j);
					}
				}
			}
		}

	}

}

//BFS算法实现思路2
int visited[100] = {0};
void BFS(MGraph G, int v0)    //vo搜索起点
{
	int i, j, v = 0;
	Queue* Q = creatQueue();
	InitQueue(Q);
	//起点入队 
	if (!visited[v0])
	{
		QueueIn(Q, v0);
		visited[v0] = 1;
		printf("%c", G.vexs[v0]);
		while (!Empty(Q))
		{
			v = QueueOut(Q);
			for (j = 1;j <= G.vexnum; j++)
			{
				if (G.arcs[v][j] == 1 && visited[j] != 1)
				{
					printf("%c", G.vexs[j]);
					visited[j] = 1;
					QueueIn(Q, j);
				}
			}
		}
	}
		
	//搜索其他树,防止森林其他树为搜索
	for (i = 1; i <= G.vexnum; i++)
	{
		if (visited[i] != 1 )
		{
	                      BFS(G, i);
		}
	}
}
void Print_MG(MGraph* mg)
{
	int i, j;
	if (mg->Type == 0)
		printf("Is Direct Graph\n");
	else
		printf("Is UNDirect Graph\n");
	for (i = 1;i <= mg->vexnum;i++)
	{
		for (j = 1;j <= mg->vexnum;j++)
		{
			printf("%d  ", mg->arcs[i][j]);//遍历输出矩阵
		}
		printf("\n");
	}
}

int main()
{
	MGraph MG;
	Creat_MG(&MG);
	Print_MG(&MG);
	printf("BFsTraverse\n");
	BFsTraverse(MG);
	printf("\nBFS\n");
	BFS(MG, 1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值