图的存储和遍历

图的存储

图的存储方式有两种:分别是邻接矩阵和邻接表;

邻接矩阵:

开一个二维数组G[i][j],值为1则说明有边,反之则0说明没有边,其值也可以存放边权。

只适用于顶点数不太大(一般不超过1000)的题目

邻接表:

用vector实现邻接表,在一些顶点数目较大(一般顶点个数在1000以上)的情况下,一般是使用邻接表而不是邻接矩阵才存储图。

图的遍历

图的遍历是指按一定顺序遍历所有顶点, 一般遍历方法有两种,分别是深度优先搜索和广度优先搜索。

记住两个步骤就好了:找出连通块(DFSTravel/BFSTravel),挖掘连通块(DFS/BFS)。

深度优先搜索遍历图:

以"深度"为关键词,沿着一条路直到无法继续前进,才退回到路径上离当前顶点最近的且有未遍历分支的岔路口,并前往访问那些未遍历的分支,直到遍历完整个图。

如果是用邻接矩阵存储图,就用以下方法遍历图:
 

//可以相互到达的结点的集合是连同块,无向图又叫做连同分量,有向图又叫做强连通分量; 
const int maxn = 10000;//最大顶点数;
const int INF = 1e6;
//邻接矩阵实现图存储;
int n, G[maxn][maxn];
bool vis[maxn] = {false};//判断该结点是否有访问;
//遍历顶点的分支;
void DFS(int u, int depth) {//顶点编号; 
	vis[u] = true;//当前顶点已被访问; 
	//此处可以对u进行一些操作;
	for(int v = 0; v < n; v++) {//对u的分支顶点进行枚举; 
		if(vis[v] == false && G[u][v] != INF){
			DFS(v, depth+1); 
		}
	} 
} 

//遍历顶点;
void DFSTrave( ) {
	for(int u = 0; u < n; u++) {//遍历图的所有顶点; 
		if(vis[u] == false) {
			DFS(u, 1);//u == 0的顶点是第一层; 
		}
	}
} 

邻接表存储图:
 

//邻接表存储图;
const int maxn = 1010;
const int INF = 1e6 + 10;
bool vis[maxn] = {false};//判断该结点是否有被访问;
 
 vector<int > Adj[maxn];//邻接表,每个vector代表每个顶点,push_back是每个顶点能直到达的顶点:
 void DFS(int u, int depth) {//要遍历的顶点;
 	vis[u] = true; 
 	for(int v = 0; v < Adj[u].size( ); v++) {//遍历u顶点下能直接到达的顶点; 
 		if(vis[v] == false) {
 			DFS(v, depth + 1);
		 }
	 } 
 } 
 
 void DFSTrave( ) {
 	for(int u = 0; u < n; u++) {//遍历图内所有顶点; 
 		if(vis[u] == false) {
 			DFS(u, 1);
		 }
	 } 
 } 

广度优先搜索遍历图:


和DFS一样,两个步骤,找出连通块,挖掘连通块,其他的和一般的BFS遍历树没什么区别;

①邻接矩阵存储图:
 

//邻接矩阵---BFS遍历图,和DFS一样,基本上就两步,一是遍历顶点找出连通块,二是挖掘出连通块;
void BFS(int u) {
	queue<int > q;
	q.push(u);
	vis[u] == true;
	while(q.empty()) {
		int u = q.front();
		q.pop();
		for(int i = 0; i < n; i++) {//不知道连通关系,就要遍历所有顶点; 
			if(vis[i] == false && G[u][i] != 0) {
				q.push(i);
				vis[i] = true;
			}
		}
	}
}

void BFSTravel () {
	for(int i = 0; i < n; i++) {
		if(vis[i] == false) {//找出连通块; 
			BFS(i);//挖掘该连通块; 
		}
	}
} 

②邻接表存储图:
 

int n;
vector<int > Adj[n];
bool vis[maxn] = {false};
void BFS(int u) {
	queue<int > q;
	q.push(u);
	vis[u] = true;
	while(!q.empty()) {
		int u = q.front();
		for(int i = 0; i < Adj[i].size(); i++) {//挖掘连通块; 
			int v = Adj[u][i];
			if(vis[v] == false){
				q.push(v);
				vis[v] = true;
			}
		}
	}
} 
void BFSTravel() {
	for(int i = 0; i < n; i++) {//找到连通块; 
		if(vis[i] == false) {
			BFS(i)//挖掘连通块; 
		}
	}
}

BFS遍历图,且给连通块内的结点分层次;

//BFS遍历图,且要输出该连通块内的所有其他顶点的层号;

struct Node {
	int v;//编号;
	int layer;
};

void BFS(int s) {//起点顶点编号;
	queue<Node> q;
	Node start;
	start.v = s;
	start.layer = 0;
	q.push(start);
	vis[s.v] = true;  
	while(!q.empty()) {
		Node top = q.front();
		q.pop();
		int u = top.v;//当前结点的编号; 
		for(int i = 0; i < Adj[u].size(); i++) {//遍历当前结点可到达的结点; 
			Node next = Adj[u][i];
			next.layer = top.layer + 1;//可直接到达的结点的层次是当前结点层次+1; 
			if(vis[next.v] == false) {
				q.push(next);
				vis[next.v] = true;
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值