邻接矩阵实现--图的深度优先遍历DFS和广度优先遍历BFS

          图论中一个基本的概念就是遍历。就是访问到图的每一个顶点,同时每个顶点只访问一次。

          DFS和BFS的概念和思路网上说明的很详细了。但是网上很多代码实现有缺陷,基本都没有考虑图不连通的情况,比如某个顶点A和其它任何一个顶点都不关联,那么这个顶点A就访问不到了。如果遍历的起点刚好是孤立的顶点A,就只能访问顶点A了,其它顶点就访问不到了。

          我这边的代码就是增加了这些情况的处理,确保每个顶点都能可以访问到。

          完整的代码如下(通过邻接矩阵实现图):

#define MAX_VERTEX 16

typedef enum
{
	UNDIRECTED_GRAPH = 0, //无向图
	DIRECTED_GRAPH = 1, //有向图
	UNDIRECTED_NET = 2, //无向网
	DIRECTED_NET = 3, //有向网
}GRAPH_TYPE;

typedef struct
{
	GRAPH_TYPE type; //图的类型
	int vertexCount;//顶点个数
	BOOL visitFlag[MAX_VERTEX];
	char vertex[MAX_VERTEX]; //顶点数组
	int edge[MAX_VERTEX][MAX_VERTEX]; //邻接矩阵
}GRAPH,*PGRAPH;

void Visit(PGRAPH graph,int vIndex)
{
	graph->visitFlag[vIndex] = TRUE; //设置已访问标志
	printf("Visit Vertex: %c\r\n",graph->vertex[vIndex]);
}

void DFS(PGRAPH graph,int startVertexIndex)
{
	stack<int> s; //访问栈
	s.push(startVertexIndex);
	while(!s.empty())
	{
		int vertexIndex = s.top();
		if(!graph->visitFlag[vertexIndex])//未访问过
		{
			Visit(graph,vertexIndex);
		}

		s.pop();//vertexIndex顶点出栈

		for(int j=graph->vertexCount-1;j>=0;j--)
		{
			if(!graph->visitFlag[j] && graph->edge[vertexIndex][j])
			{
				s.push(j); //于vertexIndex相邻的顶点并且未访问过的顶点全部入栈
			}
		}
	}

	//图并不一定是连通的,因此要确保每个顶点都遍历过
	for(int i=0;i<graph->vertexCount;i++)
	{
		if(!graph->visitFlag[i])
		{
			printf("Not Connected vertex start DFS: %c\r\n",graph->vertex[i]);
			DFS(graph,i);
		}
	}
}

void BFS(PGRAPH graph,int startVertexIndex)
{
	queue<int> q; //访问队列
	q.push(startVertexIndex);//起始访问的顶点入队

	while(!q.empty())
	{
		int vertexIndex = q.front();
		if(!graph->visitFlag[vertexIndex])//未访问过
		{
			Visit(graph,vertexIndex);
		}

		q.pop();//vertexIndex顶点出队

		for(int j=0;j<graph->vertexCount;j++)
		{
			if(!graph->visitFlag[j] && graph->edge[vertexIndex][j])
			{
				q.push(j); //于vertexIndex相邻的顶点并且未访问过的顶点全部入队
			}
		}
	}

	//图并不一定是连通的,因此要确保每个顶点都遍历过
	for(int i=0;i<graph->vertexCount;i++)
	{
		if(!graph->visitFlag[i])
		{
			printf("Not Connected vertex start BFS: %c\r\n",graph->vertex[i]);
			BFS(graph,i);
		}
	}
}

void InitGraph(PGRAPH graph)
{
	graph->type = UNDIRECTED_GRAPH; //无向图
	graph->vertexCount = 10;
	for(int i=0;i<graph->vertexCount;i++)
	{
		graph->vertex[i] = 'A'+i; //顶点为'A','B','C'等等
	}

	graph->edge[0][1] = 1;//AB有边
	graph->edge[1][0] = 1;

	graph->edge[0][4] = 1;//AE有边
	graph->edge[4][0] = 1;

	graph->edge[1][3] = 1;//BD有边
	graph->edge[3][1] = 1;

	graph->edge[2][4] = 1;//EC有边
	graph->edge[4][2] = 1;

	graph->edge[2][5] = 1;//CF CG CH 有边
	graph->edge[5][2] = 1;
	graph->edge[2][6] = 1;
	graph->edge[6][2] = 1;
	graph->edge[2][7] = 1;
	graph->edge[7][2] = 1;

	graph->edge[6][8] = 1;//GI GJ 有边
	graph->edge[8][6] = 1;
	graph->edge[6][9] = 1;
	graph->edge[9][6] = 1;
}

void InitVistFlag(PGRAPH graph)
{
	for(int i=0;i<graph->vertexCount;i++)
	{
		graph->visitFlag[i] = FALSE;
	}
}

void TestGraph()
{
	GRAPH graph = {UNDIRECTED_GRAPH,0};
	InitGraph(&graph);

	printf("Test BFS,Start vertex 0:\r\n");
	BFS(&graph,0);

	InitVistFlag(&graph);
	printf("\r\nTest DFS,Start vertex 0:\r\n");
	DFS(&graph,0);

	InitVistFlag(&graph);
	for(int i=0;i<graph.vertexCount;i++)
	{
		graph.edge[2][i] = 0;
		graph.edge[i][2] = 0;//使得第3个顶点和任何顶点都不连通
	}
	printf("\r\nTest BFS,Start vertex 5:\r\n");
	BFS(&graph,5);

	InitVistFlag(&graph);
	printf("\r\nTest DFS,Start vertex 5:\r\n");
	DFS(&graph,5);
}

邻接矩阵是一种的存储结构,它可以用来表示有限个顶点之间的关系。邻接矩阵深度优先遍历广度优先遍历的两种基本遍历方式。 邻接矩阵深度优先遍历(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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值