Kosaraju算法详解
发布时间 - 2026-01-11 03:10:44 点击率:次Kosaraju算法是干什么的?

Kosaraju算法可以计算出一个有向图的强连通分量
什么是强连通分量?
在一个有向图中如果两个结点(结点v与结点w)在同一个环中(等价于v可通过有向路径到达w,w也可以到达v)它们两个就是强连通的,所有互为强连通的点组成了一个集合,在一幅有向图中这种集合的数量就是这幅图的强连通分量的数量
怎么算??
第一步:计算出有向图 (G) 的反向图 (G反) 的逆后序排列(代码中有介绍)
第二步:在有向图 (G) 中进行标准的深度优先搜索,按照刚才计算出的逆后序排列顺序而非标准顺序
class Kosaraju {
private Digraph G;
private Digraph reverseG; //反向图
private Stack<Integer> reversePost; //逆后续排列保存在这
private boolean[] marked;
private int[] id; //第v个点在几个强连通分量中
private int count; //强连通分量的数量
public Kosaraju(Digraph G) {
int temp;
this.G = G;
reverseG = G.reverse();
marked = new boolean[G.V()];
id = new int[G.V()];
reversePost = new Stack<Integer>();
makeReverPost(); //算出逆后续排列
for (int i = 0; i < marked.length; i++) { //重置标记
marked[i] = false;
}
for (int i = 0; i < G.V(); i++) { //算出强连通分量
temp = reversePost.pop();
if (!marked[temp]) {
count++;
dfs(temp);
}
}
}
/*
* 下面两个函数是为了算出 逆后序排列
*/
private void makeReverPost() {
for (int i = 0; i < G.V(); i++) { //V()返回的是图G的节点数
if (!marked[i])
redfs(i);
}
}
private void redfs(int v) {
marked[v] = true;
for (Integer w: reverseG.adj(v)) { //adj(v)返回的是v指向的结点的集合
if (!marked[w])
redfs(w);
}
reversePost.push(v); //在这里把v加入栈,完了到时候再弹出来,弹出来的就是逆后续排列
}
/*
* 标准的深度优先搜索
*/
private void dfs(int v) {
marked[v] = true;
id[v] = count;
for (Integer w: G.adj(v)) {
if (!marked[w])
dfs(w);
}
}
public int count() { return count;}
}
为什么这样就可以算出强连通分量的数量?(稍微有些费解)
比如有这样一个图,它有五个强连通分量
我们需要证明在26行的dfs(temp)中找到的①全是点temp的强连通点,②且是它全部的强连通点
证明时不要忘了定义:v可通过有向路径到达w,w也可以到达v,则它俩强连通
先证明②:
用反证法,就假如对一个点(点w)深度优先搜索时有一个它的强连通点(点v)没找到。
如果没找到,那就说明 点v 已经在找其他点时标记过了, 但 点v 如果已经被标记过了,因为有一条 v -> w 的有向路径,那 点w 肯定也被找过了,那就不会对 点w 深度优先搜索了。
假设不成立 (*^ω^*)
再证明①:
对一个点(点w)深度优先搜索时找到了一个点(点v),说明有一条 w -> v 的有向路径,再证明有一条 v -> w 的路径就行了,证明有一条 v -> w 的路径,就相当于证明图G的反向图(G反)有一条 w -> v 的有向路径,因为 点w 和 点v 满足那个 逆后序排列,而逆后序排列是在redfs(node)结束时将node加入栈,再从栈中弹出,那说明反向图的深度优先搜索中redfs(v)肯定在redfs(w)前就结束了,那就是两种情况:
■ redfs(v)已经完了redfs(w)才开始
■ redfs(v)是在 redfs(w)开始之后结束之前 结束的,也就是redfs(v)是在redfs(w)内部结束的
第一种情况不可能,因为 G反 有一条 v -> w 的路径(因为G有一条 w -> v 的路径),满足第二中情况即在 G反 中有一条 w -> v 的路径。
终于证完了。
完整代码:
package practice;
import java.util.ArrayList;
import java.util.Stack;
public class TestMain {
public static void main(String[] args) {
Digraph a = new Digraph(13);
a.addEdge(0, 1);a.addEdge(0, 5);a.addEdge(2, 3);a.addEdge(2, 0);a.addEdge(3, 2);
a.addEdge(3, 5);a.addEdge(4, 3);a.addEdge(4, 2);a.addEdge(5, 4);a.addEdge(6, 0);
a.addEdge(6, 4);a.addEdge(6, 9);a.addEdge(7, 6);a.addEdge(7, 8);a.addEdge(8, 7);
a.addEdge(8, 9);a.addEdge(9, 10);a.addEdge(9, 11);a.addEdge(10, 12);a.addEdge(11, 4);
a.addEdge(11, 12);a.addEdge(12, 9);
Kosaraju b = new Kosaraju(a);
System.out.println(b.count());
}
}
class Kosaraju {
private Digraph G;
private Digraph reverseG; //反向图
private Stack<Integer> reversePost; //逆后续排列保存在这
private boolean[] marked;
private int[] id; //第v个点在几个强连通分量中
private int count; //强连通分量的数量
public Kosaraju(Digraph G) {
int temp;
this.G = G;
reverseG = G.reverse();
marked = new boolean[G.V()];
id = new int[G.V()];
reversePost = new Stack<Integer>();
makeReverPost(); //算出逆后续排列
for (int i = 0; i < marked.length; i++) { //重置标记
marked[i] = false;
}
for (int i = 0; i < G.V(); i++) { //算出强连通分量
temp = reversePost.pop();
if (!marked[temp]) {
count++;
dfs(temp);
}
}
}
/*
* 下面两个函数是为了算出 逆后序排列
*/
private void makeReverPost() {
for (int i = 0; i < G.V(); i++) { //V()返回的是图G的节点数
if (!marked[i])
redfs(i);
}
}
private void redfs(int v) {
marked[v] = true;
for (Integer w: reverseG.adj(v)) { //adj(v)返回的是v指向的结点的集合
if (!marked[w])
redfs(w);
}
reversePost.push(v); //在这里把v加入栈,完了到时候再弹出来,弹出来的就是逆后续排列
}
/*
* 标准的深度优先搜索
*/
private void dfs(int v) {
marked[v] = true;
id[v] = count;
for (Integer w: G.adj(v)) {
if (!marked[w])
dfs(w);
}
}
public int count() { return count;}
}
/*
* 图
*/
class Digraph {
private ArrayList<Integer>[] node;
private int v;
public Digraph(int v) {
node = (ArrayList<Integer>[]) new ArrayList[v];
for (int i = 0; i < v; i++)
node[i] = new ArrayList<Integer>();
this.v = v;
}
public void addEdge(int v, int w) { node[v].add(w);}
public Iterable<Integer> adj(int v) { return node[v];}
public Digraph reverse() {
Digraph result = new Digraph(v);
for (int i = 0; i < v; i++) {
for (Integer w : adj(i))
result.addEdge(w, i);
}
return result;
}
public int V() { return v;}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Kosaraju
# 算法
# 分享Java常用几种加密算法(四种)
# 关于各种排列组合java算法实现方法
# java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序算法的描述
# java冒泡排序算法代码
# java实现MD5加密算法的实例代码
# 史上最全的java随机数生成算法分享
# 使用java自带des加密算法实现文件加密和字符串加密
# 用java实现冒泡排序算法
# 基于Java实现的Dijkstra算法示例
# java异或加密算法
# 的是
# 弹出
# 是在
# 过了
# 几个
# 在这里
# 计算出
# 那就
# 在这
# 中有
# 到时候
# 可通过
# 图中
# 是为了
# 环中
# 有一
# 不可能
# 如有
# 两种
# 这样一个
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程
头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
Laravel如何为API生成Swagger或OpenAPI文档
Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程
网站制作大概多少钱一个,做一个平台网站大概多少钱?
JavaScript如何实现路由_前端路由原理是什么
如何在企业微信快速生成手机电脑官网?
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?
Laravel怎么在Blade中安全地输出原始HTML内容
为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】
大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?
如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体
Laravel辅助函数有哪些_Laravel Helpers常用助手函数大全
php json中文编码为null的解决办法
如何在自有机房高效搭建专业网站?
Laravel如何发送邮件和通知_Laravel邮件与通知系统发送步骤
如何撰写建站申请书?关键要点有哪些?
Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】
车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?
简历没回改:利用AI润色让你的文字更专业
Android使用GridView实现日历的简单功能
千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】
Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】
如何用腾讯建站主机快速创建免费网站?
香港服务器网站卡顿?如何解决网络延迟与负载问题?
如何选择PHP开源工具快速搭建网站?
Laravel如何自定义错误页面(404, 500)?(代码示例)
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
Python数据仓库与ETL构建实战_Airflow调度流程详解
Python正则表达式进阶教程_复杂匹配与分组替换解析
香港服务器租用费用高吗?如何避免常见误区?
企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?
Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程
Laravel如何监控和管理失败的队列任务_Laravel失败任务处理与监控
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
Laravel如何使用Spatie Media Library_Laravel图片上传管理与缩略图生成【步骤】
JavaScript中如何操作剪贴板_ClipboardAPI怎么用
Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】
Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势
矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?
html5如何设置样式_HTML5样式设置方法与CSS应用技巧【教程】
Laravel怎么写单元测试_PHPUnit在Laravel项目中的基础测试入门
悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】
公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
湖南网站制作公司,湖南上善若水科技有限公司做什么的?

