【算法与数据结构 の 相关概念】图

相关概念

图表示“多对多”的关系,包括

一组顶点(使用V表示顶点集合),表示依附于某顶点v的边数,入度表示指以顶点为终点的弧的数目,出度表示指以顶点为起点的弧的数目,领接点表示与该顶点直接相连的边。

一组边或弧(使用E表示边或弧的集合),存在于无向图中,使用无序偶对表示(v1,v2),存在于有向图中,使用有序偶对表示(v1,v2),v1表示起点,v2表示终点。权值表示对应边所赋予的一个数值。
另外两个顶点之间不存在重边和,一条边的起点和终点不能不经过任何结点然后指向自己。
在这里插入图片描述
**连通:**无向图中顶点V与W之间存在一条无向路径
**路径长度:**无权图,路径的边数之和,有权图,所有边的权值之和
**连通图:**图中任意两顶点均连通
**连通分量:**无向图的极大连通子图

**强连通:**有向图中顶点V和W之间存在双向路径
**强连通图:**有向图中任意两顶点均强连通
**强连通分量:**有向图的极大强连通子图

图的表示

邻接矩阵(更适用于稠密图(边多))

在这里插入图片描述
对于网络,则需要将G[i][j]的值定义为(v1,v2)的权重即可
在这里插入图片描述

邻接表(更适用于稀疏图(边少))

在这里插入图片描述
对于网络,则需要在指针中增加一个表示权重的数据域即可
对于有向图,则链表的第一个元素表示起点,链接的元素表示终点,这样有利查看出度,但如果要查看入度的话,需要构造“逆邻接表”(存指向自己顶点)

相关操作

创建插入

邻接矩阵

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

邻接表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

遍历

深度优先搜索(DFS)
//伪码描述:
//从第一个点出发递归遍历,当某点的周围都被遍历过一遍的话,
//则函数返回到上一层,即沿来时的路径返回,直到返回到起点为止
//类似于树的先序遍历
void DFS(Vertex V){
	visit[V]=true; 	//访问该处结点
	for(V的每一个邻接点W){	
		if(!visit[W]) 
			DFS(W);//查找该处结点的邻接点是否被访问,
	}			   //若没有被访问则进行DFS递归调用
}
广度优先搜索(BFS)
//伪码描述:
//首先压根结点入栈,当队列非空时,循环出栈队列中的元素,
//并将该元素周围的元素依次访问并压入栈
//类似于树的层序遍历
void BFS(Vertex V){
	visit[V]=true;
	Enqueue(V,Q);
	while(!Q.empty()){
		V=Dequeue(Q);
		for(V的每一个邻接点W)
			if(!visit[W]) {
				visit[W]=true;
				Enqueue(W,Q);
			}
	}
}
图不连通的遍历操作
//伪码描述:
//查看每一个结点是否有被访问,再对没有被访问过的结点进行访问,
//即可保证不连通图的遍历操作
void ListComponents( Graph G ) { 
	for( each V in G ) 
		if( !visited[V] ) { 
		DFS( V ); /*or BFS( V )*/ } 
		}
}

单源最短路径

从某固定源点出发,求其 到所有其他顶点的最短路径

无权图
//伪码描述:以BFS为参照,dist[S] = 0
//时间复杂度T= O( |V| + |E| )
void Unweighted( Vertex S ) { 
	Enqueue(S, Q); 
	while(!IsEmpty(Q)){ 
		V = Dequeue(Q); for( V 的每个邻接点W ) 
			if( dist[W]==-1  ) { 
				dist[W] = dist[V]+1; //S到W的最短距离 
				path[W] = V; //S到W的路上经过的某顶点
				Enqueue(W, Q); 
			} 
	} 
}
//这道题可以这么理解
/*********
1->2->3->4
1->4
从1出发,要寻找4的最小路径,
以1为圆心画个圆,可以发现半径为1的圆比半径为4的圆更先到达4,所以1->4即为最短路径
*********/

在这里插入图片描述

有权图
//伪码描述:Dijkstra算法(不能解决有负边的情况)
//每次从未收录的顶点V中选一个dist最小的收录
//每收录一个V都可能影响邻接点W的值
void Dijkstra( Vertex s ) {
	while(1) { 
		V = 未收录顶点中dist最小者; 
		if( 这样的V不存在) break; 
		collected[V] = true; 
		for ( V 的每个邻接点W ) 
			if( collected[W] == false ) 
				if( dist[V]+E<V,W>< dist[W] ) {						  
				  dist[W] = dist[V] + E<V,W>; 	
				  path[W] = V; 
				} 
	} 
}
//时间复杂度
//直接扫描所有未收录的T= O(|V|*|V| + |E|),有利于稠密图
//使用最小堆保存T= O(|V|log|V| + |E|log|V|) ,有利于稀疏图

在这里插入图片描述

多源最短路径

求任意两顶点间的最短路径

//方法一:直接将单源最短路算法调用|V|遍 
//时间复杂度T= O(|V|*|V|*|V| + |E|*|V|),对于稀疏图效果好
//方法二:伪码描述:Floyd算法
//时间复杂度T= O(|V|*|V|*|V|),对于稠密图效果好
//假设第k-1次递归已经完成,对于第k次递归,
//若k的加入使得D[i][k]+D[k][j]变小,则保存路径,否则不保存路径
void Floyd() {  
	for ( i = 0; i < N; i++ ) 
		for( j = 0; j < N; j++ ) { 
		//G为邻接矩阵,D保存i与j结点的的最短路径
			D[i][j] = G[i][j]; 	
			path[i][j] = -1; 
		} 
	for( k = 0; k < N; k++ ) 
		for( i = 0; i < N; i++ ) 
			for( j = 0; j < N; j++ ) 
				if( D[i][k] + D[k][j] < D[i][j] ) {
				 D[i][j] = D[i][k] + D[k][j];  
				 path[i][j] = k; 
				} 
}

AOV网络

**拓扑序:**如果图中从V到W有一条有向路径, 则V一定排在W之前。满足此条件的顶点序列 称为一个拓扑序
**AOV:**存在有合理的拓扑序,即是有向无环图
例题:

代码:

//伪码描述:
//每次循环输出无前驱顶点的顶点
//时间复杂度:T= O(|V| + |E|)
void TopSort() { 
	for( 图中每个顶点V ) 
	if( Indegree[V]==0 ) //Indegree[V]代表顶点V的入度数
		Enqueue( V, Q ); 
	while( !IsEmpty(Q) ) { 
		V = Dequeue( Q ); 
		输出V,或者记录V的输出序号; cnt++; 
		for( V 的每个邻接点W ) 
			if( ––Indegree[W]==0 ) 
			Enqueue( W, Q ); 
	} 
	if( cnt!= |V| ) Error( “图中有回路”); 
}

AOE网络

在这里插入图片描述
例题
在这里插入图片描述

判断有向图是否有环

深度优先遍历
从编号0的顶点出发,若两个顶点间存在路径,则记录下源顶点标记为已访问(标记为-1),同时判断上源顶点是否为已访问,若上源顶点未被访问则标为-1,若上源定点给已访问则说明有向图中存在环

拓扑排序
循环删除入度为0的结点,同时删除已该节点为出度的弧,若最后还剩下结点,则说明有向图内存在环

判断无向图是否有环

深度优先遍历
在搜索过程中判断是否会出现后向边(DFS中,连接顶点u到它的某一祖先顶点v的边),即在DFS对顶点进行着色过程中,若出现所指向的顶点为黑色,则此顶点是一个已经遍历过的顶点(祖先),出现了后向边,若完成DFS后,则图中有回路;

广度优先遍历
在遍历过程中,为每个节点标记一个深度deep,如果存在某个节点为v,除了其父节点u外,还存在与v相邻的节点w使得deep[v]<=deep[w]的,那么该图一定存在回路;

图的邻接表
首先统计每个顶点的度,然后重复寻找一个度为1的顶点,将度为1和0的顶点从图中删除,并将与该顶点相关联的顶点的度减1,然后继续反复寻找度为1的,在寻找过程中若出现若干顶点的度都为大于1,则这些顶点组成了一个回路;否则,图中不存在回路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值