【数据结构·考研】拓扑排序

拓扑排序-邻接矩阵

获得一个图的拓扑排序可以有深搜和广搜两种途径。深搜是逆向思维,遍历到递归最深处,层层返回的时候把结点压栈,得到的是一个逆序拓扑序列。广搜是正向思维,从度为 0 的结点入手,每次将度为 0 的结点入队,直到全部遍历。

深搜:

int visited[5] = {0};
//visited有三种状态,未搜索-0/搜索中-1/搜索完成-2
//如果一个结点dfs到一个visited为1的结点那就说明能够通过这个结点再到达自己,说明有环 

bool valid = true;//valid是标志位,初始为true,一旦出现环,置为false 
stack<char> s;//栈保存结果 

void dfs(MGraph& G,int u){
	visited[u] = 1; //搜索中
	for(int i = 0;i < G.numVertices;i ++){
		if(G.edge[u][i] > 0){ //有出边 
			if(!visited[i]) {
				dfs(G,i);
				if(!valid) return; //有环退出 
			} 
			else if(visited[i] == 1){ //有环 
				valid = false;
				return;
			}
		}
	}
	visited[u] = 2;
	s.push(G.vertice[u]); //dfs后入栈 
} 

void findOrder_dfs(MGraph& G){
	for(int i = 0;i < G.numVertices && valid;i ++)
		if(!visited[i]) dfs(G,i);
	if(!valid) return; //有环返回 
	while(!s.empty()){
		cout<<s.top()<<" ";
		s.pop();
	}
}

广搜:

queue<char> res; //队列存放结果 
int v[5] = {0}; //visited[]
int indeg[5] = {0}; //入度表 
int visit = 0; //已访问的结点数 
	
void bfs(MGraph& G,int u){
	queue<int> q;
	q.push(u);
	v[u] = true;
	while(!q.empty()){
		visit ++; //访问结点数+1 
		int w = q.front();
		res.push(G.vertice[w]); //放入结果队列
		 
		q.pop();
		for(int i = 0;i < G.numVertices;i ++){
			if(G.edge[w][i] > 0){
				indeg[i] --; //入度-1 
				if(indeg[i] == 0 && !v[i]){ //度为0入队 
					v[i] = true;
					q.push(i);
				}
			} 
		}
	}
}

void findOrder_bfs(MGraph& G){
	//初始化入边表 
	for(int i = 0;i < G.numVertices;i ++)
		for(int j = 0;j < G.numVertices;j ++)
			if(G.edge[i][j] > 0) 
				indeg[j] ++;

	for(int i = 0;i < G.numVertices;i ++)
		if(indeg[i] == 0 && !v[i]) bfs(G,i);

	if(visit != G.numVertices) return; //有环返回 
	while(!res.empty()){
		cout<<res.front()<<" ";
		res.pop(); 
	} 	
}

全部代码:

#include<iostream>
#include<queue>
#include<stack>
using namespace std;

typedef struct{
	int numVertices;
	char vertice[10];
	int edge[10][10];
}MGraph; 

//深度优先遍历 
/*
  逆向思维: 
  对于一个节点 u,如果它的所有相邻节点都已经搜索完成,那么在搜索回溯到u的时候,
  u本身也会变成一个已经搜索完成的节点。我们对图进行一遍深度优先搜索,当每个节点
  进行回溯的时候,把该节点放入栈中。最终从栈顶到栈底的序列就是一种拓扑排序。
*/ 

int visited[5] = {0};
//visited有三种状态,未搜索-0/搜索中-1/搜索完成-2
//如果一个结点dfs到一个visited为1的结点那就说明能够通过这个结点再到达自己,说明有环 

bool valid = true;//valid是标志位,初始为true,一旦出现环,置为false 
stack<char> s;//栈保存结果 

void dfs(MGraph& G,int u){
	visited[u] = 1; //搜索中
	for(int i = 0;i < G.numVertices;i ++){
		if(G.edge[u][i] > 0){ //有出边 
			if(!visited[i]) {
				dfs(G,i);
				if(!valid) return; //有环退出 
			} 
			else if(visited[i] == 1){ //有环 
				valid = false;
				return;
			}
		}
	}
	visited[u] = 2;
	s.push(G.vertice[u]); //dfs后入栈 
} 

void findOrder_dfs(MGraph& G){
	for(int i = 0;i < G.numVertices && valid;i ++)
		if(!visited[i]) dfs(G,i);
	if(!valid) return; //有环返回 
	while(!s.empty()){
		cout<<s.top()<<" ";
		s.pop();
	}
}

//广度优先遍历
/*
  正向思维: 
  我们使用一个队列来进行广度优先搜索。所有入度为0的节点都被放入队列中,
  它们就是可以作为拓扑排序最前面的节点,并且它们之间的相对顺序是无关紧要的。
*/
queue<char> res; //队列存放结果 
int v[5] = {0}; //visited[]
int indeg[5] = {0}; //入度表 
int visit = 0; //已访问的结点数 
	
void bfs(MGraph& G,int u){
	queue<int> q;
	q.push(u);
	v[u] = true;
	while(!q.empty()){
		visit ++; //访问结点数+1 
		int w = q.front();
		res.push(G.vertice[w]); //放入结果队列
		
		q.pop();
		for(int i = 0;i < G.numVertices;i ++){
			if(G.edge[w][i] > 0){
				indeg[i] --; //入度-1 
				if(indeg[i] == 0 && !v[i]){ //度为0入队 
					v[i] = true;
					q.push(i);
				}
			} 
		}
	}
}

void findOrder_bfs(MGraph& G){
	//初始化入边表 
	for(int i = 0;i < G.numVertices;i ++)
		for(int j = 0;j < G.numVertices;j ++)
			if(G.edge[i][j] > 0) 
				indeg[j] ++;

	for(int i = 0;i < G.numVertices;i ++)
		if(indeg[i] == 0 && !v[i]) bfs(G,i);

	if(visit != G.numVertices) return; //有环返回 
	while(!res.empty()){
		cout<<res.front()<<" ";
		res.pop(); 
	} 	
}

int main(){
	MGraph G;
	G.numVertices = 5;
    G.vertice[0]= 'a';
    G.vertice[1]= 'b';
    G.vertice[2]= 'c';
    G.vertice[3]= 'd';
    G.vertice[4]= 'e';
	//a
	G.edge[0][0] = 0;
	G.edge[0][1] = 1;
	G.edge[0][2] = 0;
	G.edge[0][3] = 0;
	G.edge[0][4] = 1;
	//b
	G.edge[1][0] = 0;
	G.edge[1][1] = 0;
	G.edge[1][2] = 1;
	G.edge[1][3] = 0;
	G.edge[1][4] = 0;
	//c
	G.edge[2][0] = 0;
	G.edge[2][1] = 0;
	G.edge[2][2] = 0;
	G.edge[2][3] = 1;
	G.edge[2][4] = 0; 
	//d
	G.edge[3][0] = 0; //改为1,构成了环,无拓扑序列 
	G.edge[3][1] = 0;
	G.edge[3][2] = 0;
	G.edge[3][3] = 0;
	G.edge[3][4] = 0;
	//e
	G.edge[4][0] = 0;
	G.edge[4][1] = 0;
	G.edge[4][2] = 1;
	G.edge[4][3] = 0;
	G.edge[4][4] = 0;
	
	cout<<"dfs:"<<endl;
	findOrder_dfs(G);
	cout<<endl;
	cout<<"bfs:"<<endl;
	findOrder_bfs(G);
}

运行结果:

猜你喜欢

转载自blog.csdn.net/cjw838982809/article/details/108478041