算法-强连通分量和Kosaraju算法

简介:

有向图中,连通性比较好理解,如果两个顶点V和顶点W是可达的,可以称之为强连通的,即存在路径A→B,同时也存在一条有向路径B→A.从之前的有向环的判定过程中其实我们可以得到一个结论就是两个是强连通的当且仅当它们都在一个普通的有向环中。强连通将所有的顶点分为了不同的集合,每个集合都是由相互均为强连通性的顶点的最大子集组成的,我们将这些集合称之为强连通分量。

基础概念

一般来说技术服务于生活,如果将我们看到网页作为顶点,页面指向另外一个页面的超链接作为边,可以将数量庞大的网页分为不同的大小进行处理,作为软件工程师或者说码农,经常遇到的就是模块的封装,如果将模块作为顶点,模块之间的引用作为边,通过强连通图我们可以更好进行模块之间的调用关系考虑适时的解耦。如果通过平方级别的算法解决强连通分量,那么遇到大型有向图的过程我们就会有点力不从心。Kosaraju的算法(也称为Kosaraju-Sharir算法)是线性时间的算法来解决有向图中的连通性查询以及处理强连通分量的数量。

采用之前有向环中的图片:

API定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@ interface  KosarajuCC : NSObject
 
//记录顶点是否被标记
@property  (strong,nonatomic)  NSMutableArray  *marked;
 
@property (assign,nonatomic)  NSInteger count; //连通的分量
 
@property  (strong,nonatomic)  NSMutableArray  *ids; //顶点所在的连通分量的标识符
 
//连通分量递归初始化
-(instancetype)initWithGraph:(Digraph *)graph;
 
-( void )depthSearch:(Digraph *)graph  vertex:(NSInteger)vertex;
//判断两个顶点之间是否存在连通性
-(BOOL)stronglyConnected:(NSInteger)vertex  otherVertex:(NSInteger)otherVertex;
 
@end

算法实战

通过API的定义,如果对比之前之前无向图中的API,我们发现基本上没有变化,具体实现的过程中变化也很小,需要之前基于深度优先搜索的顶点排序,取出逆后序集合进行遍历即可,之后和无向图中一样进行递归判断存储在数组中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@implementation KosarajuCC
 
#pragma mark  getter and setter
-(NSMutableArray *)marked{
     if  (!_marked) {
         _marked=[[NSMutableArray alloc]initWithCapacity:1];
     }
     return  _marked;
}
 
-(NSMutableArray *)ids{
     if  (!_ids) {
         _ids=[[NSMutableArray alloc]initWithCapacity:1];
     }
     return  _ids;
}
 
-(instancetype)initWithGraph:(Digraph *)graph{
     self=[super init];
     if  (self) {
         for  (NSInteger i=0; i<graph.vertexs;i++) {
             [self.marked addObject:[NSNull  null ]];
             [self.ids addObject:[NSNull  null ]];
         }
         DepthFirstOrder *order=[[DepthFirstOrder alloc]initWithGraph:[graph reverse]];
         //遍历图的顶点
         for  (NSInteger j=0; j<[order.reversePostStack count]; j++) {
             NSInteger  temp=[[order.reversePostStack objectAtIndex:j] integerValue];
             if  (![self isMarked:temp]) {
                 [self depthSearch:graph vertex:temp];
                 self.count++;
             }
         }
     }
     return  self;
}
//博客园-FlyElephant:http://www.cnblogs.com/xiaofeixiang/
-( void )depthSearch:(Digraph *)graph vertex:(NSInteger)vertex{
     self.marked[vertex]=[NSNumber numberWithBool: true ];
     //同一分量中顶点的赋值
     self.ids[vertex]=[NSNumber numberWithInteger:self.count];
     for  (NSInteger i=0; i<[graph.adjDataSource[vertex] count]; i++) {
         NSInteger temp=[[graph.adjDataSource[vertex] objectAtIndex:i] integerValue];
         if  (![self isMarked:temp]) {
             [self depthSearch:graph vertex:temp];
         }
     }
}
 
-(Boolean)isMarked:(NSInteger)vertex{
     return  self.marked[vertex]==[NSNull  null ]? false :[self.marked[vertex] boolValue];
}
 
-(BOOL)stronglyConnected:(NSInteger)vertex  otherVertex:(NSInteger)otherVertex{
     return  [self.ids[vertex] integerValue]==[self.ids[otherVertex] integerValue];
}
@end

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Digraph  *graph=[[Digraph alloc]initWithVertex:13];
[graph addEdges:4 endVertex:2];
[graph addEdges:2 endVertex:3];
[graph addEdges:3 endVertex:2];
[graph addEdges:6 endVertex:0];
[graph addEdges:0 endVertex:1];
[graph addEdges:2 endVertex:0];
[graph addEdges:11 endVertex:12];
[graph addEdges:12 endVertex:9];
[graph addEdges:9 endVertex:10];
[graph addEdges:9 endVertex:11];
[graph addEdges:8 endVertex:9];
[graph addEdges:10 endVertex:12];
[graph addEdges:11 endVertex:4];
[graph addEdges:4 endVertex:3];
[graph addEdges:3 endVertex:5];
[graph addEdges:7 endVertex:8];
[graph addEdges:8 endVertex:7];
[graph addEdges:5 endVertex:4];
[graph addEdges:0 endVertex:5];
[graph addEdges:6 endVertex:4];
[graph addEdges:6 endVertex:9];
[graph addEdges:7 endVertex:6];
KosarajuCC  *graphCC=[[KosarajuCC alloc]initWithGraph:graph];
for  (NSInteger i=0; i<graphCC.count; i++) {
     NSMutableArray  *dataSource=[[NSMutableArray alloc]initWithCapacity:1];
     for  (NSInteger j=0; j<graph.vertexs; j++) {
         if  ([graphCC.ids[j] integerValue]==i) {
             [dataSource addObject:[NSNumber numberWithInteger:j]];
         }
     }
     NSLog( @"分量%ld:%@" ,i,[dataSource componentsJoinedByString: @"--" ]);
}
NSInteger  vertex=0,otherVertex=1;
Boolean  cc=[graphCC stronglyConnected:vertex otherVertex:otherVertex];
NSLog( @"节点%ld和节点%ld %@强连通的" ,vertex,otherVertex,cc== true ? @"是" : @"不是" );
NSLog( @"技术交流群:%@" , @"228407086" );
NSLog( @"博客园-FlyElephant:http://www.cnblogs.com/xiaofeixiang" );

测试结果:

本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4715319.html,如需转载请自行联系原作者

相关文章
|
算法
图论——强连通分量:Tarjan算法。
在有向图G中,如果两个定点u,v间存在一条u到v的路径,也存在一条v到u的路径,则称u,v是强连通的。 若有向图G的任意两点都强联通,则称G是一个强联通图。 非强连通图的极大强连通子图称为强连通分量。   这里,极大强连通子图可以理解为一个子图是强连通图,且它的任意子图都不是强联通。
3451 0
|
算法 C++ BI
图论——强连通分量:Tarjan算法——练习1
上一次我们详细介绍了强连通分量的Tarjan算法,今天呢,我们来做一些习题来巩固Tarjan算法,毕竟它十分重要。 Tarjan算法详解 上面是上一次的详解,在做题时可供参考。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                               练习一般采用洛谷题库。
1529 0
|
存储 算法
算法学习之路|强连通分量+缩点
路漫漫其修远兮,算法学习
1870 0
|
算法
poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)
1 /* 2 题目大意:有N个cows, M个关系 3 a->b 表示 a认为b popular;如果还有b->c, 那么就会有a->c 4 问最终有多少个cows被其他所有cows认为是popular! 5 6 思路:强连通分量中每...
1116 0
|
7月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
658 0
|
7月前
|
数据采集 分布式计算 并行计算
mRMR算法实现特征选择-MATLAB
mRMR算法实现特征选择-MATLAB
424 2
|
8月前
|
传感器 机器学习/深度学习 编解码
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
351 3

热门文章

最新文章