인접 행렬/인접 목록[C/C++]에서 그래프 DFS 알고리즘의 비재귀적 구현


머리말

그래프의 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 순회 및 방문 배열 설정

비재귀적 순회든 재귀적 순회든 정점을 방문했는지 여부를 표시하기 위해 정점 테이블에 대해 방문 배열이 생성됩니다. 따라서 DFS 순회는 주로 v 정점의 순회가 다르며 여기서는 먼저 전체 그래프에 대한 방문 배열과 모든 정점의 재귀 순회를 나열합니다.

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 노드에 대한 액세스

다음은 단일 노드에 대한 순회 접근이다. 판단된다.

여기서 vi는 처음에 0이고 w를 0, 즉 수평량의 수직좌표로 설정하고 stacking을 하기 위한 조건이 무엇인지 생각해보고 우선 w 정점은 방문하지 않은, 즉 방문하였다. [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();
		}
	}
}

Supongo que te gusta

Origin blog.csdn.net/qq_45400167/article/details/125822842
Recomendado
Clasificación