图算法--图的存储和遍历

图的存储

邻接矩阵

  设图 G ( V , E ) G(V, E) G(V,E)的顶点标号为 0 , 1 , ⋯   , N − 1 0, 1, \cdots , N-1 0,1,,N1, 那么可以令二维数组 G [ N ] [ N ] G[N][N] G[N][N]的两维分别表示图的顶点标号,即如果 G [ i ] [ j ] G[i][j] G[i][j]为1, 则说明顶点i和j之间有边;如果 G [ i ] [ j ] G[i][j] G[i][j]为0,则说明顶点i和顶点j之间不存在边,这个二维数组被称为邻接矩阵
  如果存在边权,则可以令 G [ i ] [ j ] G[i][j] G[i][j]存放边权,对不存在的边可以设边权为0、-1或是一个很大的数。
  邻接矩阵只适合用于顶点数目不太大(一般不超过1000)的情况。

邻接表

  由于vector有变长数组之称,因此可以用vector数组 A d j [ N ] Adj[N] Adj[N],其中 N N N为顶点个数,来存储邻接表。

  • 如果邻接表只存放每条边的终点编号,而不存放边权:
    vector<int> Adj[N]; \\定义int型的vector数组存储邻接表
    Adj[1].push_back(3); \\添加一条从1号顶点到达3号顶点的有向边
  • 如果需要同时存放边的终点编号和边权:
//方法一:
//定义Node型的vector数组存储邻接表
struct Node{
	int v;	//边的终点编号
	int w;	//边权
	}
vector<Node> Adj[N];

//添加从1号到达3号顶点的有向边,边权为4
Node temp;
temp.v = 3;
temp.w = 4;
Adj[1].push_back(temp);



//方法二:
//定义Node型的vector数组存储邻接表
struct Node{
   int v, w;
   Node(int _v, int _w): v(_v), w(_w){}	//构造函数
   }
vector<Node> Adj[N];

//添加从1号到达3号顶点的有向边,边权为4	
Node temp(3, 4);
Adj[1].push_back(temp);

图的遍历

采用深度优先搜索(DFS)法遍历图

  沿着一条路径直到无法继续前进,才退回到路径上离当前顶点最近的还存在未访问分支顶点的岔道口,并前往访问那些未访问分支顶点,直到遍历完整个图。

  • 连通分量:无向图中,图G的任意两个顶点都连通(即两个顶点之间可以通过一定路径相互到达),则称图G为连通图。非连通图中的极大连通子图,称为连通分量
  • 强连通分量:有向图中,任意两个顶点都强连通, 则称图G为强连通图。非强连通图的极大强连通子图,称为强连通分量

DFS Code

const int MAXV = 1000;	//最大顶点数
const int INF = 1000000000;	//设INF为一个很大的数

//方法一:邻接矩阵版
int n, G[MAXV][MAXV];	//n为顶点数,MAXV为最大顶点数
bool vis[MAXV] = {false};	//如果顶点i已被访问,则vis[i] == true.

void DFS(int u, int depth){	//u为当前访问的顶点标号, depth为深度
	vis[u] = true;	//设置u已被访问
	for(int v = 0; v < n; v++ ){
		if(vis[v] == false && G[u][v] != INF){
			DFS(v, depth + 1);              //访问v, 深度加1
		}
	}
}

//遍历图G
//如果要遍历整个图,就需要对所有连通块分别进行遍历。
void DFSTrave(){		
	for(int u = 0; u < n; u++){	
		if(vis[u] == false){	
			DFS(u, 1);
		}	
	}
}

//方法二:邻接表版 
int n;
vector<int> Adj[MAXV];	//图G的邻接表
bool vis[MAXV] = {false};

void DFS(int u, int depth){
	vis[MAXV] = true;
	for(int i = 0; i < Adj[u].size(); i++){
		v = Adj[u][i];
		if(vis[v] == false){
			DFS(v, depth + 1);
		}
	}
}

void DFSTrave(){
	for(int u = 0; u < n; u++){
		if(vis[u] == false){
			DFS(u, 1);
		}
	}
}

采用广度优先搜索(BFS)法遍历图

  如果要遍历整个图,则需要对所有连通块分别进行遍历。使用BFS遍历图的基本思想是建立一个队列,并把初始顶点加入队列,此后每次都取出队首顶点进行访问,并把从该顶点出发可以到达的未曾加入过队列的顶点全部加入队列,直到队列为空。

BFS Code

//方法一: 零阶矩阵版
int n, G[MAXV][MAXV];	//n为顶点数, MAXV最大顶点数
bool inq[MAXV] = {false};	//若顶点i曾入过队列,则inq[i] == true。初值为false

void BFS(int u){	//遍历u所在的连通块
	queue<int> q;	//定义队列q
	q.push(u);	//将初始点u入列
	inq[u] = true;	//设置u已被加入过队列
	while(! q.empty){	//只要队列非空
		int u = q.front();	//取出队首元素
		q.pop();	//将队首元素出队
		for(int v = 0; v < n; v++){
			if(G[u][v] != INF &&  inq[v] == false){
				q.push(v);
				inq[v] == true;
			}
		}
	}
}

void BFSTrave(){
	for(int u = 0; u < n; u++){	//枚举所有顶点
		if(inq[u] == false){	//如果u未曾加入过队列
			BFS(q);	//遍历u所在的连通块
		}
	}
}


//方法二:邻接表版
struct Node{
	int v;	//顶点编号
	int layer;	//顶点层号
};
vector<Node> Adj[N];
int n;
bool inq[MAX];

void BFS(int s){	//s为起始顶点编号
	queue<Node> q;	//BFS队列
	Node start;	//起始顶点
	start.v = s;	//起始顶点编号
	start.layer = 0; 	//起始顶点层号为0
	q.push(start);	//将起始顶点压入队列
	inq[start.v] = true;	//起始顶点的编号设为已被加入过队列
	while(!q.empty()){
		Node topNode = q.front();	//取出队首顶点
		q.pop();	//队首顶点出队
		int u = topNode.v;	//队首顶点的编号
		for(int i = 0; i < Adj[u].size(); i++){
			Node next = Adj[u][i]
			next.layer = topNode.layer + 1;	//next层号等于当前顶点层号加1
			//如果next的编号未被加入过队列
			if(inq[next.v] == false){
				q.push(next);	//将next入队
				inq[next.v] = true;	//next的编号设为已被加入过队列
			}
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值