基于邻接矩阵和邻接表的两种方法实现无向图的BFS和DFS

广度优先搜索(Breadth-First-Search)和深度优先搜索(Deep-First-Search)是搜索策略中最经常用到的两种方法,特别常用于图的搜索.

BFS的思想:

从一个图的某一个顶点V0出发,首先访问和V0相邻的且未被访问过的顶点V1、V2、……Vn,然后依次访问与V1、V2……Vn相邻且未被访问的顶点。如此继续,找到所要找的顶点或者遍历完整个图。我们采用队列来存储访问过的节点。

DFS的思想:

深度优先搜索所遵循的策略就是尽可能“深”的在图中进行搜索,对于图中某一个顶点V,如果它还有相邻的顶点且未被访问,则访问此顶点。如果找不到,则返回到上一个顶点。这一过程一直进行直到所有的顶点都被访问为止。 DFS可以搜索出从某一个顶点到另外的一个顶点的所有路径。 由于要进行返回的操作,我们采用的是递归的方法。

邻接表:

邻接表是图的一种链式存储结构。在邻接表中,对图中的每个顶点vi建立一个单链表,把鱼vi相邻的顶点放在这个链表中。

邻接矩阵:

邻接矩阵是表示顶点之间相邻关系的矩阵。设G(V,E)是具有n个顶点的无向图,则其对应了一个n阶方阵。设这个方阵为A,则对于A[i][j]有两种取值,当A[i][j]=1时,表示顶点i和顶点j是连通的;当A[i][j]=0时,表示顶点i和顶点j是不连通的。

基于邻接矩阵的DFS:

<span style="font-size:14px;">//基于邻接矩阵的DFS,时间复杂度为O(n^2)
#include <stdio.h>
#include <string.h>
const int GNumber = 8;//存储节点个数
int G[GNumber][GNumber];//存储邻接矩阵
int color[GNumber];//存储节点状态

void DFS_Visit(int G[][GNumber], int i, int n){
	int j;
	color[i] = 1;
	for(j=0; j< n; j++){
		if(G[i][j] && !color[j]){
			printf(" V%d ", j+1);
			color[j] = 1;
			DFS_Visit(G, j, n);
		}
	}
}

void DFS(int G[][GNumber], int n){
	int i;
	memset(color, 0, sizeof(color));
	for(i=0; i<n; i++){//遍历每一个节点
		if(!color[i]){//判断是否访问
			printf(" V%d ", i+1);
			DFS_Visit(G,i,n);
			printf("\n");
		}
	}
}

int main(){
	FILE *fr;
	int i,j;
	fr = fopen("测试用例.txt","r");
	if(!fr){
		printf("fopen failed\n");
		return -1;
	}
	while(fscanf(fr,"%d%d", &i, &j) != EOF){
		G[i-1][j-1] = 1;
		G[j-1][i-1] = 1;
	}
	DFS(G,GNumber);
	getchar();
	return 0;
}</span>

基于邻接矩阵的BFS:

<span style="font-size:14px;">//基于邻接矩阵的BFS,时间复杂度为O(n^2)
#include <stdio.h>
#include <string.h>

const int GNumber = 8;//存储节点个数
int G[GNumber][GNumber];//存储邻接矩阵
int color[GNumber];// 防止回环,记录节点状态 

struct Queue{//用数组模拟队列
	int queue[GNumber];
	int start;
	int end;
}MyQueue;

void BFS(int G[][GNumber], int n){
	int j;
	MyQueue.queue[MyQueue.end++] = 0;
	color[0] = 1;
	while(MyQueue.end != MyQueue.start){
		for(j=0; j<n; j++){
			if(G[MyQueue.start][j] && !color[j]){
				color[j] = 1;
				MyQueue.queue[MyQueue.end++] = j;
			}
		}
		printf(" V%d ", MyQueue.queue[MyQueue.start++]+1);
	}
}

int main(int argc, char **argv){
	FILE *fr;
	int i,j;
	fr = fopen("测试用例.txt","r");
	if(!fr){
		printf("fopen failed\n");
		return -1;
	}
	//printf("%d %d\n",MyQueue.start,MyQueue.end);
	while(fscanf(fr,"%d%d", &i, &j) != EOF){
		G[i-1][j-1] = 1;
		G[j-1][i-1] = 1;
	}
	memset(&MyQueue, 0, sizeof(MyQueue));
	memset(color, 0, sizeof(color));
	BFS(G,GNumber);
	getchar();
	return 0;
}</span>

基于邻接表的BFS和DFS:

<span style="font-size:14px;">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX  8   //最大顶点数

typedef struct node{ //边节点
        int adjvex;  //该边指向的顶点位置
        //int weight
        struct node* next;  //指向下一条边的指针
}ArcNode;//边表结点

typedef struct VNode{
        int vertex;
        ArcNode* firstarc; //指向第一条依附该顶点的指针
}VNode;//顶点表结点

typedef VNode Adjlist[MAX+1];//adj_list是邻接表类型

typedef struct {
        int n, m;//图中顶点数和边数
        Adjlist adjlist;//邻接表
}ALGraph;

void create_algraph(ALGraph* g)//建立无向图的邻接表
{
	ArcNode* newnode;
    int i, j, k;
	printf("please input node number and edge number: ");
	scanf("%d%d", &g->n, &g->m);
	printf("node number = %d, edges = %d\n", g->n, g->m);
	for(i = 1; i <= g->n; i++){
		g->adjlist[i].vertex = i;
		g->adjlist[i].firstarc = NULL;
	}
	printf("please input new edge: \n");//用相邻的两个顶点来表示边
	for(k = 1; k <= g->m; k++){
		scanf("%d%d", &i, &j);
		//printf("\n");
		newnode = (ArcNode* )malloc(sizeof(ArcNode));
		newnode->adjvex = j;
		//newnode->weight = 0;
		newnode->next = g->adjlist[i].firstarc;
		g->adjlist[i].firstarc = newnode;
		newnode = (ArcNode* )malloc(sizeof(ArcNode));
		newnode->adjvex = i;
		//newnode->weight = 0;
		newnode->next = g->adjlist[j].firstarc;
		g->adjlist[j].firstarc = newnode;
	}
}

void pr_algraph(ALGraph* g)//输出邻接表
{
	ArcNode* node;
	int i;
	for(i = 1; i<= g->n; i++){
		node = g->adjlist[i].firstarc;
		printf("g->adjlist[%d] = %d: ", i, g->adjlist[i].vertex);
		while(node != NULL){
				printf("%d \t", node->adjvex);
				node = node->next;
		}
		printf("\n");
	}
}

int visted[MAX+1];//记录节点状态
void DFS(ALGraph *g,int v)
{
	visted[v] = 1;			//访问初始点
	ArcNode *p = g->adjlist[v].firstarc;
	while(p!=NULL)
	{
		if (visted[p->adjvex]==0){	//如果没有被访问过,则递归调用DFS访问
			printf("%d ",p->adjvex);
			DFS(g,p->adjvex);
		}
		p = p->next;//继续下一条边
	}
	//printf("\n");
}

void BFS(ALGraph *g,int v)
{
	//for (int i=0;i<g->n;i++) visted[i] = 0;
	int queue[MAX],front,rear;
	front = rear = 0;
	rear = (rear+1)%MAX;
	queue[rear] = v; //v顶点入队
	int u;
	ArcNode *p;
	while(/*rear!=0*/front!=rear)//当队列满时
	{
		front = (front+1)%MAX;
		u = queue[front];
		p = g->adjlist[u].firstarc;
		while(p!=NULL)	//首先访问u的所有节点
		{
			if (visted[p->adjvex]==0)
			{
				visted[p->adjvex] = 1;	//访问p->adjvex节点,标记为访问
				rear = (rear+1)%MAX;
				printf("%d ",p->adjvex);
				queue[rear] = p->adjvex;	//p->adjvex节点入队
			}
			p = p->next;
		}
	}
	printf("\n");
}

int main(int argc, char** argv)
{
	ALGraph* g;//定义一个无向图

	g = (ALGraph* )malloc(sizeof(ALGraph));
	printf("begin create algraph\n");
	create_algraph(g);
	printf("finish create algraph\n");

	printf("the algraph is:\n");
	pr_algraph(g);
	memset(visted,0,sizeof(visted));
	visted[1]=1;
	printf("BFS is:\n");
	printf("1 ");
	BFS(g,1);
	memset(visted,0,sizeof(visted));
	printf("DFS is:\n");
	printf("1 ");
	DFS(g,1);
	printf("\n");
	return 0;
}

</span>

邻接矩阵和邻接表都是实现BFS和DFS的方法,邻接矩阵时间复杂度为O(n^2),邻接表的时间复杂度为O(n+e);因此邻接矩阵适用于稠密图,邻接表适用于稀疏图。

时间: 2024-10-30 10:46:42

基于邻接矩阵和邻接表的两种方法实现无向图的BFS和DFS的相关文章

shell 脚本实现乘法口诀表的两种方法——shell与C语言

shell 脚本实现乘法口诀表的两种方法--shell与C语言 话不多说直接给出代码: 1 #!/bin/bash 2 if [ $# -eq 0 ] //用于判断输入的参数个数为0 3 then 4 echo "welcome you!" 5 echo "this is a test with 2 methods to output arbitrarily mux table!" 6 else 7 echo "sorry you input invlia

如何删除windows服务(sc.exe删除和注册表删除两种方法)

一.什么是Windows服务 Windows服务也称为Windows Service,它是Windows操作系统和Windows网络的基础,属于系统核心的一部分,它支持着整个Windows的各种操作.诸如DNS客户端.打印程序.Windows更新服务.计划任务.Windows时间服务.告警器等服务,它们关系到机器能否正确运行.如果不能适当地管理这些服务,就会影响到机器的正常操作.    一个服务首先是一个Win32可执行程序,或者是是rundll32.exe来运行一个.dll的方式形成的进程.跟

打印九九乘法表的两种方法

#1.for循环 rows,cols = xrange(1,10),xrange(1,10) row,col = 1,1 for row in rows: for col in cols: if col <= row: print '%d*%d=%d\t' % (col,row,col*row), #\t代表tab键, 逗号确保同rows在同一行 print #打印空格,确保同col在同一列 可以简化为: for rows in xrange(1,10): for cols in xrange(

重连通量的邻接矩阵和邻接表两种形式的求法

邻接矩阵: #include <cstdio> #include <cstring> #include <stack> using namespace std; #define min(a,b) a<b?a:b #define N 105 int dfn[N],low[N],mat[N][N],visit[N],tmpdfn,n; struct Edge{ int x,y; void print(){ printf("%d-%d\n",x,y)

图的两种存储(邻接矩阵和邻接表)和两种遍历(DFS和BFS)

图的表示有很多,形式不固定,我暂时先记录我已经懂了的,能写的两种即大多数人应该都知道的邻接矩阵和邻接表. 邻接矩阵: 这里的邻接矩阵和离散数学说的有一点不同,至少有向图的邻接矩阵不同(离散书上的有向图的邻接矩阵求法到是有点像求任意两点的最短路径的Floyd算法) 以上都是(我现有知识认为的)废话: 重点 : G : 表示图: Nv:表示图的点数: Ne:表示图的边数: 邻接矩阵 即是一个 Nv * Nv 的矩阵,矩阵是用来储存  权值的(如果是带权图且有边的话),如果是无权图的的话,如果两顶点有

基于邻接表的图建立(有向图+无向图)

图的表示(建立)有两种方法: ①邻接矩阵:A(i,j)=1表示i,j存在一条边,空间复杂度O(n^2),稠密图 ②邻接表:只记录存在的边,Vector+List的数据结构,稀疏图 邻接矩阵的图建立这里不做赘述,接下来我们看一下邻接表的图建立: <1>有向图 注意理解头插入节点的过程 int n,m;//n表示城镇个数,m表示道路条数</span> struct LinkNode//列表节点 { int vex; //邻接的结点在数组中的编号 LinkNode* next; }; s

数据结构基础 之 通过邻接矩阵与邻接表 图 实现

[邻接矩阵] 邻接矩阵,就是一个反应边与边之间联系的二维数组.这个二维数组我们用matrix[numV][numV]表示,其中numV是顶点数. 对于无权图 若顶点Vi和Vj之间有边,则matrix[Vi][Vj]=1;否则matrix[Vi][Vj]=0. 对于有权图 若顶点Vi和Vj之间有边,且权值为weight,则matrix[Vi][Vj]=weight;否则matrix[Vi][Vj]=0或MAXWEIGHT(取最小权值或最大权值). [邻接表] 当图中的边数较少时,用邻接矩阵来实现图

图的存储结构:邻接矩阵(邻接表)&amp;链式前向星

[概念]疏松图&稠密图: 疏松图指,点连接的边不多的图,反之(点连接的边多)则为稠密图. Tips:邻接矩阵与邻接表相比,疏松图多用邻接表,稠密图多用邻接矩阵. 邻接矩阵: 开一个二维数组graph[ ][ ]来记录图中点a与点b之间是否连通,初始化为0(或者-1之类的看情况):如果图中有可忽略的重边(如 只需重边中的最小边或最大边),则保存需要的那条边的边权,但如果有无法忽略的重边,就一定不要用邻接矩阵. int graph[MAXN][MAXN]; void graphInit() { me

无向图的表示:邻接矩阵和邻接表

这里将一个无向图用邻接表和邻接矩阵表示. 输入:顶底个数n,图中的各个边(用两个顶点表示). 输出:这个无线图的邻接矩阵和邻接表,其中邻接表中的链接按元素大小升序排列. 先给出一个例子说明.假设有无向图如下,则其邻接矩阵和邻接表如提示框中所示(其实就是下面程序的输出). 下面是程序的代码: #include <stdio.h> #include <stdlib.h> //图的表示,输入节点个数和边,构造图的邻接矩阵和邻接表 //邻接表中的链表节点 struct vNode{ int