算法-图论_关键节点的判断
2014-04-04 12:30
155 查看
无向图的关节点
概述:
在网络中关节点的判断将成为影响网络连通性的主要因素。节点之间通过关键点传递信息,如在我们以太网中的网关。当网关节点失效,那么两个网络之间的节点就不能够进行通信。在无线传感器网络中,会造成不能及时监控部分区域的信息。这次程序主要实现一个简单的判断关键节点方法,当然关键节点不能单靠两个节点之间的连通与否简单判断。算法思想:
符合关键节点的条件为:后继结点不能访问该节点的父节点。也就是说只能通过该节点才能实现网络节点间的连通性。如何的判断后继节点不能访问父节点?父节点如何的定义?我们很熟悉的就是利用DFS能够判断网络的连通性。因此我们依旧采用这种方式。假设一个图为如下所示:
那么它的深度优先遍历将会如下图所示:
图中的实线为深度优先遍历产生的树,虚线为节点的后向边。标注的后向边为节点能访问到最前的后向边。
由此可以利用一个计数来表示访问当前节点顺序。由此在访问子节点时其访问顺序必定会大于树中的父节点。如此保证了每个节点的唯一的一个编号,就如ID一样。再加一个表示后向边指向的在树中最高的节点Pred。一旦这个pred的值大于它的父节点,那么就说明它可以绕过父节点访问树中上面的节点。在图中,如f节点,尽管是从c节点遍历访问的,但是因为有指向a的后向边,a的计数小于c的计数(num),因此我们把f的pred指向a。
如何在代码中判断c是否为关节点。因为其子节点的pred<c的计数,所以我们认为c不是关键节点。那么节点对应的数据结构如下:
//判断连通性的节点定义 struct ConnectNode { int key;//键值 int num;// int pred;//前向边的索引 bool bKeyNode; }; //解释:在识别连通性时,将连接节点的边分为前向边与后向边
其中bKeyNode是为了判断该节点是否为关节点,防止在第一副图中b判断一次d节点,e又判断一个d节点,结果输出两次的情况。
但是还要注意的一个小细节是:当从a开始访问,c节点的后向边为a,肯定的是c.pred值将为a.num。因此我们需要判断节点是否为根节点且其孩子的个数。由此下面为联通图判断关键节点的类。
//连通性的图 class ConnectGraph { public: int nodeNum;//节点个数 int **Matrix;//利用邻接矩阵存储数据 ConnectNode* nodes;//节点 int *keynodes;//存放关键节点 int resultPos; int count; bool **visitedMatrix; int headChild; }
其中count用以为每个节点的num赋值,保证唯一性。而visitedMatrix为了防止c访问a,a访问c这种不断的循环。将对应的边访问置为true进行避免。
程序的代码如下:
void blockSearch()//将网络按照关键节点分为若干块 { //主要思想:对每个节点存放前向边 connectGraph(&nodes[0],&nodes[0]);//循环是避免 cout<<endl<<"关节点为:"; for (int i=0;i<resultPos;i++) { cout<<" "<<keynodes[i]; } cout<<endl<<totalCount; } void connectGraph(ConnectNode* node,ConnectNode* headNode)//判断是否连通 { node->num=++count; node->pred=node->num; for (int i=0;i<nodeNum;i++) { int nodeKey=node->key; if(visitedMatrix[nodeKey][i]==false&&Matrix[nodeKey][i]==1) { if (nodes[i].num==0) { visitedMatrix[nodeKey][i]=visitedMatrix[i][nodeKey]=true; if (node==headNode) { headChild++; } connectGraph(&nodes[i],headNode); if (nodes[i].pred>=node->num&&!node->bKeyNode) { if (node==headNode&&headChild<2) { continue;//防止出现从a开始但是子节点的pred不能大于头节点判断头结点为关节点 } else { node->bKeyNode=true;//设置节点的关键节点为true keynodes[resultPos++]=node->key; } } else { if (node->pred>nodes[i].pred)//将子节点更高的前驱赋予此节点 { node->pred=nodes[i].pred; } } }//有一种情况是当节点不能前向到父节点之前的边,但是其它的由父节点引出的边可以到达 else { //防止节点的前向边指向父节点,进而产生多次的赋值 if (node->pred>nodes[i].num)//将较小的值赋予 { node->pred=nodes[i].num;//为什么这后面又是num了呢? } } } } }
相信上面的代码很简单,首先要判断当前节点是否已经被访问过了,没有则必须进行DFS算法。当该子节点都访问了之后判断pred值。
if (node->pred>nodes[i].pred)//将子节点更高的前驱赋予此节点 { node->pred=nodes[i].pred; }
当其pred的值更小,那么将子节点的pred赋予该节点,表示父节点能够通过子节点访问到更高的节点,这里不用担心会不会跨过关键点。因为所遍历的是子节点的。
如果子节点已经被访问过了,我们看到这条语句是。
if (node->pred>nodes[i].num)//将较小的值赋予 { node->pred=nodes[i].num;//为什么这后面又是num了呢? }
仔细想想注释中的疑问。因为如果当前节点为关键节点的子节点,那么它的一个邻居节点很可能就是关键节点,而关键节点的前驱很可能就是另一个连通块中的点的num。如果进行像上一条一样的复制,就等于说关键节点的子节点能够绕过关键节点,访问另一个图。
程序的运行结果为:
小结:
1) 通过前面的图的连通性或者是树的遍历,我发现以一个全局变量进行描述,比如该程序中的num,以及在检测环时的int* num数组都是这样的一个辅助效果。2) 算法要深入的分析,就如何的判断根节点是否为关键点,我想了很多钟方案,包括1、是不是已经被访问过,其上一次被访问是否为根节点,等等。其实一个技术headChild就可以解决。减少计算的复杂度。
3) 本算法的时间复杂度还是比较高的。
相关文章推荐
- 【算法分析】如何理解快慢指针?判断linked list中是否有环、找到环的起始节点位置。以Leetcode 141. Linked List Cycle, 142. Linked List Cycle II 为例Python实现
- C++算法之 求二叉树中叶子节点的个数 与 判断两棵二叉树是否结构相同
- 数据结构实验之图论三:判断可达性(DFS算法)
- 围住神经猫判断围住的算法--简单图论
- 笔试算法题(27):判断单向链表是否有环并找出环入口节点 & 判断两棵二元树是否相等
- 【算法之链表(一)】判断单链表中是否有环、环的长度、环的入口节点,单链表的倒数第K个节点等
- 算法面试题之求前1000大&在树上判断节点父子关系
- 数据结构和算法设计专题之---判断单链表中是否有环,环的长度,环的入口节点
- 笔试算法题(19):判断两条单向链表的公共节点 & 字符集删除函数
- 数据结构实验之图论三:判断可达性(BFS算法)
- 算法2.分治算法 芯片判断好坏
- 设计一个算法,求非空二叉树中指定的第k层(k>1)的叶子节点的个数
- 用asp判断某IP是否属于一个网段的另类算法
- 判断三维模型是否是闭合的算法
- 破解 crackme4(深入底层抓出关键算法)
- 算法:求解AOE网的关键路径
- 判断一个点是不是在三角形中 用面积算法
- HDU 2444 The Accomodation of Students(最大二分匹配(匈牙利算法)+二分图判断->模板题目)
- 判断多个时间段是否重合的算法
- 算法面试题之判断整数是否可以被3整除