数据结构之图的关节点和重连通分量
2014-10-16 19:31
781 查看
本着业界良心,我感觉这个链接中关于图的关节点讲得很不错。什么是关节点?在某图中,若删除顶点V以及V相关的边后,图的一个连通分量分割为两个或两个以上的连通分量,则称顶点V为该图的一 个关节点。
如图所示,图中有四个关节点A/B/D和G,如顶点B和它的边被删除,图就会被分为3个连通分量A,C,F,L,M,J;G,H,I,K;D,E.一个没有关节点的连通图称为重连通图,上图显然不是重连通图
利用深度优先搜索便可以求的图的关节点,本由此可判别图是否重连通。
上图右边是从顶点A出发深度优先搜索遍历所得的深度优先生成树。对于树中任一顶点V而言,其孩子节点为邻接点。由深度优先生成树可得出两类关节点的特性:
(1)若生成树的根有两棵或两棵以上的子树,则此根顶点必为关节点。因为图中不存在连接不同子树顶点的边,若删除此节点,则树便成为森林。
(2)若生成树中某个非叶子顶点V,其某棵子树的根和子树中的其他节点均没有指向V的祖先的回边,则V为关节点。因为删去v,则其子树和图的其它部分被分割开来
若对图Graph=(V,{Edge}) 重新定义遍历时的访问函数visited,并引入一个新的函数low,则由一次深度优先遍历便可求得连通图中存在的所有关节点。
定义visited[v]为深度优先搜索遍历连通图时访问顶点v 的次序号;定义:
对于某个顶点v,存在孩子结点w 且low[w]≧visited[v],则该顶点v 必为关节点。因为当w 是v 的孩子结点时,low[w]≧visited[v],表明w 及其子孙均无指向v 的祖先的回边。由定义可知,visited[v]值即为v 在深度优先生成树的前序序列的序号,只需将DFS 函数中头两个语句改为visited[v0]=++count(在DFSTraverse 中设初值count=1)即可;low[v]可由后序遍历深度优先生成树求得,而v
在后序序列中的次序和遍历时退出DFS 函数的次序相同,由此修改深度优先搜索遍历的算法便可得到求关节点的算法.
代码如下(注释比较详细了):
贴个测试代码:
完整的源码看:GitHub
如图所示,图中有四个关节点A/B/D和G,如顶点B和它的边被删除,图就会被分为3个连通分量A,C,F,L,M,J;G,H,I,K;D,E.一个没有关节点的连通图称为重连通图,上图显然不是重连通图
利用深度优先搜索便可以求的图的关节点,本由此可判别图是否重连通。
上图右边是从顶点A出发深度优先搜索遍历所得的深度优先生成树。对于树中任一顶点V而言,其孩子节点为邻接点。由深度优先生成树可得出两类关节点的特性:
(1)若生成树的根有两棵或两棵以上的子树,则此根顶点必为关节点。因为图中不存在连接不同子树顶点的边,若删除此节点,则树便成为森林。
(2)若生成树中某个非叶子顶点V,其某棵子树的根和子树中的其他节点均没有指向V的祖先的回边,则V为关节点。因为删去v,则其子树和图的其它部分被分割开来
若对图Graph=(V,{Edge}) 重新定义遍历时的访问函数visited,并引入一个新的函数low,则由一次深度优先遍历便可求得连通图中存在的所有关节点。
定义visited[v]为深度优先搜索遍历连通图时访问顶点v 的次序号;定义:
对于某个顶点v,存在孩子结点w 且low[w]≧visited[v],则该顶点v 必为关节点。因为当w 是v 的孩子结点时,low[w]≧visited[v],表明w 及其子孙均无指向v 的祖先的回边。由定义可知,visited[v]值即为v 在深度优先生成树的前序序列的序号,只需将DFS 函数中头两个语句改为visited[v0]=++count(在DFSTraverse 中设初值count=1)即可;low[v]可由后序遍历深度优先生成树求得,而v
在后序序列中的次序和遍历时退出DFS 函数的次序相同,由此修改深度优先搜索遍历的算法便可得到求关节点的算法.
代码如下(注释比较详细了):
/* * @description:求关节点,关节点的定义;假如删除顶点v及相关各边后,将图的一个 联通分量分割成两个或是两个以上的联通分量,则顶点v为图的关节点 * @more:注意根节点的情况是需要单独处理的,其关节点成立的条件是: 生成树的根有两棵或两颗以上的子树 因为图中不存在连接不同子树的根节点的边,这样在遍历子树的过程, 会存在有节点子树是无法遍历到的,这样把根节点删除后,就会把图分成 森林 */ void FindArticul(ALGraph G) { int i,v; ArcNode *p; count = 1; low[0] = visited[0] = 1; //表示邻接表上0号顶点为生成树的根 //标志其他的节点都没有访问 for(i = 1; i < G.vexnum ; i++) visited[i] = FALSE; p = G.vertices[0].firstarc; v = p->adjvex; DFSArticul(G,v); //从第一个邻接点开始进行查找 if(count < G.vexnum ) { //根节点为关节点,输出 printf("%d,%d\n",0,G.vertices[0].data); //继续往下找 while(p->nextarc) { p = p->nextarc; v = p->adjvex; if(visited[v] == 0) DFSArticul(G,v); } } } /* * @descirption:从第v的节点出发深度优先遍历图查找图的关节点 * @more:注意visited[]现在不再是单纯的访问标志(0/1)而是1/vexnum-1, 是通过深度优先搜索遍历得到的,且在遍历的过程的中生成树中 父亲节点的总是并孩子节点先遍历到 而low[]是类似后序遍历得到的,也就是说孩子节点是先于父亲节点 遍历到的 */ void DFSArticul(ALGraph G,int v) { int min,w; ArcNode *p; //v是第count访问的节点 visited[v] = min = ++count; //对v的每个邻接点进行遍历 for(p = G.vertices[v].firstarc ; p ; p = p->nextarc ) { //w是v的邻接点 w = p->adjvex; //w未曾访问,是v的孩子 if(visited[w] == 0) { //返回前求得low[w] DFSArticul(G,w); /*如果v的孩子节点的low小,说明其还有祖先节点和孩子节点相连, 这也是为什么上面要先返回low[w]的原因 */ if(low[w] < min) min = low[w]; if(low[w] >= visited[v]) printf("%d,%d\n",v,G.vertices[v].data); } //w已经访问过,w是v0在生成树上的祖先 else if(visited[w] < min) min = visited[w]; } /* v的节点的low为visited[v]/low[w]/visited[k]中最小的 w是顶点v的在深度优先生成树上的孩子节点 k是顶点v在深度优先生成树有回边连接的祖先节点 */ low[v] = min; Order_Low[v] = lowcount++; //用于理解 }
贴个测试代码:
/*--------------------------------------------------------------------------- * file:ALGraph.c * date:10-14-2014 * author:doodlesomething@163.com * version:1.0 * description:邻接表实现图的基本操作及求图的关节点 ----------------------------------------------------------------------------*/ #include <stdio.h> #include "findarticul.h" int main() { int i; ALGraph G; //创建图 CreateGraph(&G); //深度优先遍历图 DFSTraverse(G,PrintElem); printf("\n"); //求关节点 FindArticul(G); printf("i G.vertices[i].data visited[i] low[i] Order_Low\n"); for(i = 0; i < G.vexnum ; i++) printf("%d %d %d %d %d\n",i,G.vertices[i].data,visited[i],low[i],Order_Low[i]); return 0; /* please enter the kind of graph(DG:0,DN:1,UDG:2,UDN:3):2 please the vexnum and arcnum:13,17 please enter the value of each vertex:1,2,3,4,5,6,7,8,9,10,11,12,13 please enter the heads and tails: 1,2 1,3 1,6 1,12 2,3 2,4 2,7 2,8 2,13 4,5 7,8 7,9 7,11 8,11 10,12 10,13 12,13 >>(可以看到2输出了两次,这是因为删除2会将图分割成三颗树) 1 2 3 4 5 7 8 11 9 13 10 12 6 6,7 1,2 3,4 1,2 0,1 i G.vertices[i].data visited[i] low[i] Order_Low 0 1 1 1 0 1 2 5 1 9 2 3 12 1 8 3 4 10 5 7 4 5 11 10 6 5 6 13 1 12 6 7 8 5 3 7 8 6 5 5 8 9 9 8 2 9 10 4 2 1 10 11 7 5 4 11 12 2 1 11 12 13 3 1 10 */ }
完整的源码看:GitHub
相关文章推荐
- 数据结构实验:连通分量个数
- SDUT 1488 数据结构实验:连通分量个数
- 【数据结构_图_1065】无向图连通分量计算
- SDUT 1488 数据结构实验:连通分量个数(无向图的连通)
- 数据结构实验:连通分量个数
- 数据结构——图 连通图与连通分量
- 【数据结构笔记】5:图的邻接表结构下求无向图的连通分量
- SDUT 1488 数据结构实验:连通分量个数
- SDUTOJ(1488)数据结构实验:连通分量个数
- 数据结构实验:连通分量个数
- 数据结构实验:连通分量个数
- 暑假集训 8.17 数据结构实验:连通分量个数(并查集判断连通分量个数 路径压缩)sdutoj1488
- 数据结构实验:连通分量个数(并查集)
- 数据结构实验:连通分量个数(并查集)
- 数据结构实验:连通分量个数
- 数据结构实验:连通分量个数
- 数据结构实验:连通分量的个数
- 数据结构与算法--图论之寻找连通分量、强连通分量
- 数据结构实验:连通分量个数1488
- 数据结构之图-连通分量