▶ 书中第四章部分程序,包括在加上自己补充的代码,包括无向图连通分量,Kosaraju - Sharir 算法、Tarjan 算法、Gabow 算法计算有向图的强连通分量

● 无向图连通分量

 package package01;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Graph;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.EdgeWeightedGraph;
import edu.princeton.cs.algs4.Edge; public class class01
{
private boolean[] marked;
private int[] id; // 连通分量的标号
private int[] size; // 连通分量顶点数
private int count; // 连通分量数 public class01(Graph G)
{
marked = new boolean[G.V()];
id = new int[G.V()];
size = new int[G.V()];
for (int v = 0; v < G.V(); v++)
{
if (!marked[v])
{
dfs(G, v);
count++;
}
}
} public class01(EdgeWeightedGraph G) // 有边权的图,算法相同,数据类型不同
{
marked = new boolean[G.V()];
id = new int[G.V()];
size = new int[G.V()];
for (int v = 0; v < G.V(); v++)
{
if (!marked[v])
{
dfs(G, v);
count++;
}
}
} private void dfs(Graph G, int v)
{
marked[v] = true;
id[v] = count; // 深度优先搜索时,顶点分类,连通分量尺寸更新
size[count]++;
for (int w : G.adj(v))
{
if (!marked[w])
dfs(G, w);
}
} private void dfs(EdgeWeightedGraph G, int v)
{
marked[v] = true;
id[v] = count;
size[count]++;
for (Edge e : G.adj(v))
{
int w = e.other(v);
if (!marked[w])
dfs(G, w);
}
} public int id(int v)
{
return id[v];
} public int size(int v)
{
return size[id[v]];
} public int count()
{
return count;
} public boolean connected(int v, int w)
{
return id[v] == id[w];
} public static void main(String[] args)
{
In in = new In(args[0]);
Graph G = new Graph(in);
class01 cc = new class01(G);
int m = cc.count();
Queue<Integer>[] components = (Queue<Integer>[]) new Queue[m]; // 每个连通分量放入一个队列
for (int i = 0; i < m; i++)
components[i] = new Queue<Integer>();
for (int v = 0; v < G.V(); v++)
components[cc.id(v)].enqueue(v); StdOut.println(m + " components");
for (int i = 0; i < m; i++)
{
for (int v : components[i])
StdOut.print(v + " ");
StdOut.println();
}
}
}

● Kosaraju - Sharir 算法计算有向图的强连通分量

 package package01;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Digraph;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.DepthFirstOrder; public class class01
{
private boolean[] marked;
private int[] id;
private int[] size;
private int count; public class01(Digraph G)
{
DepthFirstOrder dfs = new DepthFirstOrder(G.reverse()); // 对 G 的逆图进行深度优先搜索
marked = new boolean[G.V()];
id = new int[G.V()];
size = new int[G.V()];
for (int v : dfs.reversePost()) // 使用 G 逆图 dfs 序对 G 进行深度优先搜索
{
if (!marked[v])
{
dfs(G, v);
count++;
}
}
} private void dfs(Digraph G, int v)
{
marked[v] = true;
id[v] = count;
size[count]++;
for (int w : G.adj(v))
{
if (!marked[w])
dfs(G, w);
}
} public int id(int v)
{
return id[v];
} public int size(int v)
{
return size[id[v]];
} public int count()
{
return count;
} public boolean strongConnected(int v, int w)
{
return id[v] == id[w];
} public static void main(String[] args)
{
In in = new In(args[0]);
Digraph G = new Digraph(in);
class01 scc = new class01(G);
int m = scc.count();
Queue<Integer>[] components = (Queue<Integer>[]) new Queue[m];
for (int i = 0; i < m; i++)
components[i] = new Queue<Integer>();
for (int v = 0; v < G.V(); v++)
components[scc.id(v)].enqueue(v); StdOut.println(m + " components");
for (int i = 0; i < m; i++)
{
for (int v : components[i])
StdOut.print(v + " ");
StdOut.println();
}
}
}

● Tarjan 算法计算有向图的强连通分量

 package package01;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Digraph;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.Stack; public class class01
{
private boolean[] marked;
private int[] id;
private int[] size;
private int[] low; // 遍历序中顶点 v 的最小深度
private int pre; // 优先级(遍历顶点时不断维护)
private int count;
private Stack<Integer> stack; public class01(Digraph G)
{
marked = new boolean[G.V()];
id = new int[G.V()];
size = new int[G.V()];
low = new int[G.V()];
stack = new Stack<Integer>();
for (int v = 0; v < G.V(); v++) // 正常顺序深度优先遍历图
{
if (!marked[v])
dfs(G, v);
}
} private void dfs(Digraph G, int v)
{
marked[v] = true;
low[v] = pre++; // 更新递归深度
int min = low[v]; // 记录 v 所在的的递归深度
stack.push(v);
for (int w : G.adj(v))
{
if (!marked[w])
dfs(G, w);
if (low[w] < min) // 寻找 v 邻居的最小深度,low[w] < min 说明找到了后向边(v->w 关于栈中的元素构成有向环)
min = low[w];
}
if (min < low[v]) // 改写 v 的最小深度,终止递归(沿着栈一路改写回去,直到栈中首次出现有向环的元素为止(再往前的顶点满足 low[x] < min),进入吐栈环节
{
low[v] = min;
return;
}
int sizeTemp = 0;
for (int w = -1; w != v; sizeTemp++) // 从栈顶吐到 v 为止,都是一个强连通分量,这里 v 是有向环首元再往前一格的顶点
{
w = stack.pop();
id[w] = count; // 标记吐出的强连通分量
low[w] = G.V(); // 将已经记录了的连通分量的深度改为图的顶点数(递归可能的最大深度)
}
size[count] = sizeTemp;
count++; // 增加连通分量计数
} public int id(int v)
{
return id[v];
} public int size(int v)
{
return size[id[v]];
} public int count()
{
return count;
} public boolean strongConnected(int v, int w)
{
return id[v] == id[w];
} public static void main(String[] args)
{
In in = new In(args[0]);
Digraph G = new Digraph(in);
class01 scc = new class01(G);
int m = scc.count();
Queue<Integer>[] components = (Queue<Integer>[]) new Queue[m];
for (int i = 0; i < m; i++)
components[i] = new Queue<Integer>();
for (int v = 0; v < G.V(); v++)
components[scc.id(v)].enqueue(v); StdOut.println(m + " components");
for (int i = 0; i < m; i++)
{
for (int v : components[i])
StdOut.print(v + " ");
StdOut.println();
}
}
}

● Gabow 算法计算有向图的强连通分量

 package package01;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Digraph;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.Stack; public class class01
{
private boolean[] marked;
private int[] id;
private int[] size;
private int[] preOrder; // 记录每个顶点的遍历深度
private int pre;
private int count;
private Stack<Integer> stack1;
private Stack<Integer> stack2; // 用栈来代替 Tarjan 算法中的 low 数组 public class01(Digraph G)
{
marked = new boolean[G.V()];
id = new int[G.V()];
size = new int[G.V()];
preOrder = new int[G.V()];
stack1 = new Stack<Integer>();
stack2 = new Stack<Integer>();
for (int v = 0; v < G.V(); v++)
id[v] = -1;
for (int v = 0; v < G.V(); v++)
{
if (!marked[v])
dfs(G, v);
}
} private void dfs(Digraph G, int v)
{
marked[v] = true;
preOrder[v] = pre++; // 更新递归深度,一旦写入就不改变了
stack1.push(v); // 同时压两个栈
stack2.push(v);
for (int w : G.adj(v))
{
if (!marked[w])
dfs(G, w);
else if (id[w] == -1) // 已经遍历过 w,且 w 不属于任何连通分量
for (; preOrder[stack2.peek()] > preOrder[w]; stack2.pop()); // 把 stack2 中深度大于 w 的顶点全部吐掉(直到栈顶等于有向环的首个元素为止)
}
if (stack2.peek() == v) // 该式在递归回退到栈中首次出现有向环元素的那层时成立,此时 stack2 顶为有向环首元,stack1 顶为有向环末元
{ // 注意此时 stack2 顶层下(stack1 和 stack2 共有且相等)可能还有其他元素,是不属于非有向环部分的遍历路径
stack2.pop(); // stack2 退到首元的上一个元
int sizeTemp = 0;
for (int w = -1; w != v; sizeTemp++) // 同样的方法从 stack1 中逐渐吐栈,计算连通分量元素
{
w = stack1.pop();
id[w] = count;
}
size[count] = sizeTemp;
count++;
}
} public int id(int v)
{
return id[v];
} public int size(int v)
{
return size[id[v]];
} public int count()
{
return count;
} public boolean strongConnected(int v, int w)
{
return id[v] == id[w];
} public static void main(String[] args)
{
In in = new In(args[0]);
Digraph G = new Digraph(in);
class01 scc = new class01(G);
int m = scc.count();
Queue<Integer>[] components = (Queue<Integer>[]) new Queue[m];
for (int i = 0; i < m; i++)
components[i] = new Queue<Integer>();
for (int v = 0; v < G.V(); v++)
components[scc.id(v)].enqueue(v); StdOut.println(m + " components");
for (int i = 0; i < m; i++)
{
for (int v : components[i])
StdOut.print(v + " ");
StdOut.println();
}
}
}

《算法》第四章部分程序 part 10的更多相关文章

  1. 《算法》第四章部分程序 part 18

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,在有权有向图中寻找环,Bellman - Ford 算法求最短路径,套汇算法 ● 在有权有向图中寻找环 package package01; impo ...

  2. 《算法》第四章部分程序 part 19

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,有边权有向图的邻接矩阵,FloydWarshall 算法可能含负环的有边权有向图任意两点之间的最短路径 ● 有边权有向图的邻接矩阵 package p ...

  3. 《算法》第四章部分程序 part 16

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,Dijkstra 算法求有向 / 无向图最短路径,以及所有顶点对之间的最短路径 ● Dijkstra 算法求有向图最短路径 package packa ...

  4. 《算法》第四章部分程序 part 15

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,Kruskal 算法和 Boruvka 算法求最小生成树 ● Kruskal 算法求最小生成树 package package01; import e ...

  5. 《算法》第四章部分程序 part 14

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,两种 Prim 算法求最小生成树 ● 简单 Prim 算法求最小生成树 package package01; import edu.princeton ...

  6. 《算法》第四章部分程序 part 9

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,两种拓扑排序的方法 ● 拓扑排序 1 package package01; import edu.princeton.cs.algs4.Digraph ...

  7. 《算法》第四章部分程序 part 17

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,无环图最短 / 最长路径通用程序,关键路径方法(critical path method)解决任务调度问题 ● 无环图最短 / 最长路径通用程序 pa ...

  8. 《算法》第四章部分程序 part 13

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,图的前序.后序和逆后续遍历,以及传递闭包 ● 图的前序.后序和逆后续遍历 package package01; import edu.princeto ...

  9. 《算法》第四章部分程序 part 12

    ▶ 书中第四章部分程序,包括在加上自己补充的代码,图的几种补充数据结构,包括无向 / 有向符号图,有权边结构,有边权有向图 ● 无向符号图 package package01; import edu. ...

随机推荐

  1. ubuntu base make 未找到命令

    引用:https://blog.csdn.net/fenglibing/article/details/7096556 1.先放入UBUNTU安装盘到光盘中: 2.再按顺序执行以下的命令: sudo ...

  2. 让Netbeans 8.0 支持 Python 编程

    发布人 admin. 分类 Python, 技术手札 Netbeans版本:Netbeans 8.0 for PHP Python版本:python 2.7.8 1.添加插件更新中心 打开Netbea ...

  3. CAD 中绘制点

    首先开启点样式,否则点是看不到的 系统变量 PDMODE 和 PDSIZE 控制点对象的显示外观. PDMODE 取值为 0.2.3 .4 时指定表示点的图形,取值为 1 表示不显示任何图形,如下图所 ...

  4. Tribon/AM 数据库名字的含义

    收集在这里备用 数据库名 Tribon环境变量 内容描述 船体型线数据库 SB_CGDB 船体外型信息 型表面,船体曲线,板缝 船体结构数据库 SB_OGDB 船体模型信息 板材数据库 SB_PLDB ...

  5. 关于Javascript闭包(Closure)

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  6. 树莓派Raspberry Pi zero w无线联网实测

    第一次学习树莓派,使用的是Raspberry Pi zero w的型号. 刚开始,就只有一块板子!!!这要怎么开发啊 经过网上查阅资料,发现可以通过WiFi连接PC端实现开发测试 准备材料:一根USB ...

  7. 【枚举类型】Restful API请求--转换String为枚举类型

    IBaseEnum.java public interface IBaseEnum { public String getName(); } FuncEnum.java import com.sssl ...

  8. sass之为什么要使用预处理器

    使用预处理器主要目的就是编写出可读性更好.更易于维护的css. 以sass为例,sass中提供了@import可以在sass文件中导入其他sass文件,或在选择器中按需导入所需要的某个属性样式: @i ...

  9. Oracle ORA 6510

    解决方法待补充 咨询得到的解析是: plsql写的存储过程在导出后需要重新编译才能执行:需要处理好这方面的关系

  10. Abp.AutoMapper扩展(1) --static class AutoMapExtensions

    // 摘要:        //     Converts an object to another using AutoMapper library. Creates a new object    ...