Kosaraju算法---求解强连通分量
2015-12-26 15:13
405 查看
有向图强连通分量在有向图G中,如果两个顶点Vi,Vj间(Vi>Vj)有一条从Vi到Vj的有向路径,同时还有一条从Vi到Vj的有向路径,则称这两个顶点强。连通(strongly connected),如果有向图G中的任意两个顶点都强连通,则称G是一个强连通图。
Kosaraju算法、Tarjan算法、Gabow算法皆为寻找有向图强连通分量的有效算法。但是在Tarjan 算法和 Gabow 算法的过程中,只需要进行一次的深度优先搜索,而Kosaraju算法需要两次DFS,因而相对 Kosaraju 算法较有效率。这些算法可简称为SSC(strongly connected components)算法;
Kosaraju 算法即为算法导论一书给出的算法,比较直观和易懂。这个算法可以说是最容易理解,最通用的算法,其比较关键的部分是同时应用了原图G和反图GT。 它利用了有向图的这样一个性质,一个图和他的transpose graph(边全部反向)具有相同的强连通分量!
1) 创建一个空的栈 ‘S’ ,然后对图做DFS遍历. 在顶点访问完成后加入栈中。访问完成是说回溯返回时,而不是第一次发现该节点时。fillOrder()函数
2) 得到图转置,即将所有边反向。
3) 从S中依次弹出每个顶点,设为 ‘v’. 将v看做遍历的源点 (调用 DFSUtil(v)). 做第二次DFS遍历,可以找到以v为起点的强连通分量,打印出即可。
Kosaraju算法、Tarjan算法、Gabow算法皆为寻找有向图强连通分量的有效算法。但是在Tarjan 算法和 Gabow 算法的过程中,只需要进行一次的深度优先搜索,而Kosaraju算法需要两次DFS,因而相对 Kosaraju 算法较有效率。这些算法可简称为SSC(strongly connected components)算法;
Kosaraju 算法即为算法导论一书给出的算法,比较直观和易懂。这个算法可以说是最容易理解,最通用的算法,其比较关键的部分是同时应用了原图G和反图GT。 它利用了有向图的这样一个性质,一个图和他的transpose graph(边全部反向)具有相同的强连通分量!
## 算法步骤 ##
1) 创建一个空的栈 ‘S’ ,然后对图做DFS遍历. 在顶点访问完成后加入栈中。访问完成是说回溯返回时,而不是第一次发现该节点时。fillOrder()函数
2) 得到图转置,即将所有边反向。
3) 从S中依次弹出每个顶点,设为 ‘v’. 将v看做遍历的源点 (调用 DFSUtil(v)). 做第二次DFS遍历,可以找到以v为起点的强连通分量,打印出即可。
## 代码 ##
#include<iostream> #include<list> #include<stack> using namespace std; class Graph { int V; //顶点个数 list<int> *adj; //邻接表 void fillOrder(int V, bool visited[], stack<int> &stack);//最晚完成的遍历顶点放在栈顶 void DFSUtil(int v, bool visited[]);//DFS打印以V为起点的边 public: Graph(int V); void addEdge(int v, int w); void printSCCs();//打印所有的连通分量 Graph getTranspose();//得到当前图的转置图 }; Graph::Graph(int V) { this->V = V; adj = new list<int>[V]; } void Graph::DFSUtil(int v, bool visited[]) { visited[v] = true; cout << v << " "; list<int>::iterator i; for (i = adj[v].begin(); i != adj[v].end();i++) { if (!visited[*i]) { DFSUtil(*i, visited); } } } Graph Graph::getTranspose() { Graph g(V); for (int v = 0; v < V;v++) { list<int>::iterator i; for (i = adj[v].begin(); i != adj[v].end();++i) { g.adj[*i].push_back(v); } } return g; } void Graph::addEdge(int v, int w) { adj[v].push_back(w); } void Graph::fillOrder(int v, bool visited[], stack<int> &stack) { visited[v] = true; list<int>::iterator i; for (i = adj[v].begin(); i != adj[v].end();i++) { if (!visited[*i]) { fillOrder(*i, visited, stack); } } stack.push(v); } void Graph::printSCCs() { stack<int> stack; bool *visited = new bool[V]; for (int i = 0; i < V;i++) { visited[i] = false; } for (int i = 0; i < V;i++) { if (visited[i]==false) { fillOrder(i, visited, stack);//根据完成时间压入栈中,而栈顶是完成时间最晚的顶点; } } //下面,我们来创建转置图 Graph gr = getTranspose(); //准备第二次DFS for (int i = 0; i < V;i++) { visited[i] = false; } while (stack.empty()==false) { int v = stack.top(); stack.pop(); //打印以v为起点的强连通分量 if (visited[v]==false) { gr.DFSUtil(v, visited); cout << endl; } } } //测试程序 int main() { // 创建图 Graph g(5); g.addEdge(1, 0); g.addEdge(0, 2); g.addEdge(2, 1); g.addEdge(0, 3); g.addEdge(3, 4); cout << "Following are strongly connected components in given graph \n"; g.printSCCs(); return 0; }
相关文章推荐
- 设置progressbar的背景颜色
- c# 串口数据接收
- 学习笔记1: Activity 生命周期
- Android之获取手机上已安装的所有的应用程序的信息,并判断是否安装了某应用程序(系统程序或非系统应用程序判断)
- 单例设计模式的两种方法
- dorado框架中的级联实现
- Oracle相关操作
- Swift学习笔记(八)
- 打怪升级
- win10怎么安装Google Earth(谷歌地球)?win10安装Google Earth Pro的教程
- UI学习第03天
- 电话黑名单、来电进行监听录音
- no symbol version for module_layout
- selenium2 页面对象模型Page Object
- [置顶]关于java中根据身份证求生日和年龄的问题
- [置顶]java开发之基础篇2
- 将博客搬至CSDN
- 虚拟机vmware 安装Ubuntu上不了网
- android——fragment长时间home或者锁屏java.lang.IllegalArgumentException:No view found for id for....
- 百度搜索附近加盟店等基于LBS云搜索功能的实现