图的DFS算法在邻接矩阵/邻接表下的非递归实现【C/C++】


前言

自己在学习图的DFS遍历时,对于书上的非递归形式的DFS过于简单,在写代码时难以下手。记录一下自己的思路。


步骤如下

1.创建有向/无向图

首先应当创建一个有向图/无向图,这个比较简单。对于无向图来说,将有向图的权值信息按对称矩阵复制一份即可。

//求顶点位置函数
int LocateVertex(AdjMatrix* G, VertexData v) {
    
    
	int j, k;
	for (k = 0; k < G->vexnum; k++) {
    
    
		if (G->vertex[k] == v) {
    
    
			j = k;
			break;
		}
	}
	return j;
}

//建立有向网图的邻接矩阵表示
void CreateAdjMatrix(AdjMatrix* G) {
    
    
	int i, j, k, weight;
	VertexData v1, v2;
	printf("输入顶点数和边数\n");
	scanf("%d,%d", &G->vexnum, &G->arcnum);
	//对边表初始化
	for (i = 0; i < G->vexnum; i++) {
    
    
		for (j = 0; j < G->vexnum; j++) {
    
    
			G->arcs[i][j].adj = INFNITY;
		}
	}
	printf("输入顶点表\n");
	for (i = 0; i < G->vexnum; i++) {
    
    
		scanf(" %c", &G->vertex[i]);
	}
	printf("输入边表\n");
	for (k = 0; k < G->arcnum; k++) {
    
    
		scanf(" %c, %c,%d", &v1, &v2, &weight);
		i = LocateVertex(G, v1);
		j = LocateVertex(G, v2);
		G->arcs[i][j].adj = weight;
		//加上下面这行这就创建无向图。
		G->arcs[j][i].adj = G->arcs[i][j].adj;
	}
}

2.对于邻接矩阵的DFS遍历

接下是对于邻接矩阵的DFS遍历,递归遍历比较简单,这里就不写了。

重点是非递归遍历。

2.1邻接矩阵全节点的DFS遍历以及设置visited数组

无论是非递归遍历还是递归遍历,都会对顶点表创建一个visited数组,用来标志对该顶点是否访问过。所以对于DFS遍历来说,主要是对于v顶点的遍历不同,这里先列出对于整张图的设置visited数组和对全顶点的递归遍历。

int visited[MAX];
void NoReTraverseGraph(AdjMatrix g) {
    
    
	//设置visited数组
	for (int vi = 0; vi < g.vexnum; vi++) {
    
    
		visited[vi] = 0;
	}
	//对全顶点遍历
	for (int vi = 0; vi < g.vexnum; vi++) {
    
    
		if (!visited[vi]) {
    
    
			NoReDepthFirstSearch(g, vi);
		}
	}
}

2.2邻接矩阵vi节点的访问

接下是对单个节点的遍历访问,这里采用了stack容器来保存访问过的节点,对于最开始访问的节点vi,毫不犹豫进行入栈,再对vi的横向量的矩阵列进行判断。

这里vi最开始为0,那么设置w为0,即为横向量的纵坐标,想一想入栈的条件是什么,首先是w顶点没访问过,即visited[w]==0,并且和vi有连接,即g.arc[vi][w]==1,然后入栈,因为是深度优先,因此立刻停止搜索,按照w为顶点进行遍历。w则成为栈顶元素,因此在遍历横向量前应该先获取栈顶元素。

那么怎么出栈呢?那当然是w搜了一圈,没发现有连接的点或者都访问过了,简单点来说就是w>=边表的大小了,搜出去了都,当然要退栈了。

思路分析完毕,代码如下。

void NoReDepthFirstSearch(AdjMatrix g, int v) {
    
    
	printf("%c ", g.vertex[v]);
	//visit(v);
	visited[v] = 1;
	stack<int>S;
	S.push(v);
	while (!S.empty()) {
    
    
		int top = S.top();
		int w = 0;
		for (w = 0; w < g.vexnum; w++) {
    
    
			//如果没访问过并且还连着就访问入栈。
			if (!visited[w] && g.arcs[top][w].adj == 1) {
    
    
				printf("%c ", g.vertex[w]);
				//visit(w);
				visited[w] = 1;
				S.push(w);
				//立刻停止,对连着的这个元素进行遍历。(深度优先)
				break;
			}
		}
		//找了一圈都访问了或者都没连上,那就出栈。
		if (w == g.vexnum) {
    
    
			S.pop();
		}
	}
}

3.对于邻接表的DFS遍历

  • 学会邻接矩阵,对邻接表照猫画虎也能写出来了。
  • 代码如下
//邻接表非递归实现DFS
int visited[MAX];
void NoReDepthFirstSearch(AdjList g, int v0) {
    
    
	//visit(v0);printf("%c",g.vertexlist[v0].data);
	visited[v0] = 1;
	stack<int>S;
	S.push(v0);
	while (!S.empty()) {
    
    
		int top = S.top();
		ArcNode* p = g.vertexlist[top].firstarc;
		while (p != NULL) {
    
    
			if (!visited[p->adjvex]) {
    
    
				//visit(p->adjvex);printf("%c",g.vertexlist[p->adjvex].data);
				visited[p->adjvex] = 1;
				S.push(p->adjvex);
				break;
			}
		}
		if (p == NULL) {
    
    
			S.pop();
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_45400167/article/details/125822842