图的几种遍历方式

1.图的遍历方式大概也就两种吧,DFS和BFS。但是有不同的实现方式,上次听说我在递归转非递归算法中实现了二叉树的递归转非递归,然后有人说那图的呢?其实图的DFS转成非递归还要简单一些。

2.首先是BFS,BFS其实很简单了。使用队列来保存与当前节点相邻的所有节点,然后用这些节点作为基础继续拓展。我们这里首先给出图的定义和初始化的代码。

#define MAX 10
typedef struct graph
{
	int n;   //顶点数
	int e;  //边数
	int edge[MAX][MAX];  
}Graph;
int visit[MAX];
void InitGraph(Graph &G)
{
	for (int i = 0; i < MAX; i++)
		for (int j = 0; j < MAX; j++)
			G.edge[i][j] = 0;
}

这是一个有向图,如果有链接的边我们把这个边初始化为非零的数字。一般使用这个边的边权来初始化这个数据。但是这里我们假定如果有连边存在那么这个边缘数组被初始化为1,那么BFS的写法就是这样的。

//广度优先搜索算法
void BFS(Graph G, int num)  //num为从该点开始进行搜索
{
	queue<int>Queue;
	cout << num << " ";
	visit[num] = 1;
	Queue.push(num);  //访问完该点后入队列
	while (!Queue.empty())  //队列不为空时
	{
		num = Queue.front();  //出队
		Queue.pop();
		for (int i = 0; i < G.n; i++)
		{
			if (G.edge[num][i] != 0 && visit[i] == 0)   //找到与之相连的顶点入队
			{
				cout << i << " ";
				Queue.push(i);
				visit[i] = 1;
			}
		}
	}
	cout << endl;
}

有了BFS那么下一个就是DFS了。深度优先搜索我们一般都是用递归写的,但是肯定也是可以采用非递归实现的。我们这里还是先实现一下递归。我们知道DFS的思想就是找到一条路之后继续向下寻找,而不是扩大寻找的点。这样写成代码大概就是这样的

void DFS(Graph G, int num) //深度优先搜索递归算法,G还是图,num还是搜索的起点
{
	int i;
	cout << num << " ";//输出
	visit[num] = 1;//标记这里已经访问过
	for (i = 0; i < G.n; i++)
	{
		if (G.edge[num][i] != 0 && visit[i] == 0)
			DFS(G, i);//找到邻接的点向下访问
	}
}

递归写的很简单,但是我们现在把它转化为非递归的实现。递归转非递归肯定是要用到栈了。我们来模拟这个递归的过程,访问到某一个节点之后,我们寻找他的下一个节点,并且把这个节点压进栈中然后弹出来依次访问这个栈中的元素。即可达到效果。为什么会是这个样子呢?我们来简单的解释一下,我懒得画图了,解跟着我想象吧。假设我们1号节点链接了2和3那么我们从一号开始,访问1之后2和3就会被压进栈中,有人可能有疑惑?那这不就是BFS吗?因为所有与它相邻的节点又被拿出来了。没错,的确是被拿出来了,但是我们没有访问啊。假设现在栈中已经有了2和3中,我们在进行第二步循环的时候就会以2位起点来找到和2相邻的点,这样找下去其实这个搜索的确实是在深入的。因为虽然我们把所有相邻的点都拿出来放进栈中了,但是我们没有一次 他她们全部访问而是一个一个的访问。利用了栈的特性实现了DFS的非递归。其实也很简单的吧下面是实现的代码:

void dfs(Graph G, int Num)
{
	stack<int>st;
	visit[Num] = 1;
	st.push(Num);
	while (!st.empty())
	{
		Num = st.top();
		st.pop();
		cout << Num <<" ";
		for (int i = G.n - 1; i >= 0; i--)
		{
			if (G.edge[Num][i] != 0 && visit[i] == 0)
			{
				st.push(i);
				visit[i] = 1;
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_41863129/article/details/85250487