《算法》第四章部分程序 part 8
▶ 书中第四章部分程序,包括在加上自己补充的代码,图中找欧拉路径
● 无向图中寻找欧拉路径,只注释了与欧拉环不同的地方
package package01; import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.GraphGenerator;
import edu.princeton.cs.algs4.Graph;
import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.BreadthFirstPaths; public class class01
{
private Stack<Integer> cycle = new Stack<Integer>(); private static class Edge
{
private final int v;
private final int w;
private boolean isUsed; public Edge(int v, int w)
{
this.v = v;
this.w = w;
isUsed = false;
} public int other(int vertex)
{
if (vertex == v)
return w;
if (vertex == w)
return v;
throw new IllegalArgumentException("\n<other> No such vertex.\n");
}
} public class01(Graph G)
{
if (G.E() == 0)
return;
int oddDegreeVertices = 0; // 记录奇数度点的数量
int s = nonIsolatedVertex(G); // 选一个非孤立点为起点,有奇数度点的话要更换
if (G.E() == 0) // 认为无边的图也存在欧拉路径,这与欧拉环不同
s = 0;
else // 其他情况照常处理
{
for (int v = 0; v < G.V(); v++)
{
if (G.degree(v) % 2 != 0)
{
oddDegreeVertices++;
s = v;
}
}
if (oddDegreeVertices > 2) // 奇数度点多于 2,不存在欧拉路径
return;
Queue<Edge>[] adj = (Queue<Edge>[]) new Queue[G.V()];
for (int v = 0; v < G.V(); v++)
adj[v] = new Queue<Edge>();
for (int v = 0; v < G.V(); v++)
{
boolean selfEdge = false;
for (int w : G.adj(v))
{
if (v == w)
{
if (!selfEdge)
{
Edge e = new Edge(v, w);
adj[v].enqueue(e);
adj[w].enqueue(e);
}
selfEdge = !selfEdge;
}
else if (v < w)
{
Edge e = new Edge(v, w);
adj[v].enqueue(e);
adj[w].enqueue(e);
}
}
}
}
Stack<Integer> stack = new Stack<Integer>();
stack.push(s);
for (path = new Stack<Integer>(); !stack.isEmpty();)
{
int v = stack.pop();
for (; !adj[v].isEmpty();)
{
Edge edge = adj[v].dequeue();
if (edge.isUsed)
continue;
edge.isUsed = true;
stack.push(v);
v = edge.other(v);
}
path.push(v);
}
if (path.size() != G.E() + 1)
path = null;
} public Iterable<Integer> path()
{
return path;
} public boolean hasEulerianPath()
{
return path != null;
} private static int nonIsolatedVertex(Graph G)
{
for (int v = 0; v < G.V(); v++)
{
if (G.degree(v) > 0)
return v;
}
return -1;
} private static boolean satisfiesNecessaryAndSufficientConditions(Graph G)
{
if (G.E() == 0) // 认为没有变的图也有欧拉路径,统计奇数度的顶点
return true;
int oddDegreeVertices = 0;
for (int v = 0; v < G.V(); v++)
{
if (G.degree(v) % 2 != 0)
oddDegreeVertices++;
}
if (oddDegreeVertices > 2)
return false;
BreadthFirstPaths bfs = new BreadthFirstPaths(G, nonIsolatedVertex(G));
for (int v = 0; v < G.V(); v++)
{
if (G.degree(v) > 0 && !bfs.hasPathTo(v))
return false;
}
return true;
} private static void unitTest(Graph G, String description)
{
System.out.printf("\n%s--------------------------------\n", description);
StdOut.print(G);
class01 euler = new class01(G);
System.out.printf("Eulerian path: ");
if (euler.hasEulerianCycle())
{
for (int v : euler.cycle())
System.out.printf(" %d", v);
}
System.out.println();
} public static void main(String[] args)
{
int V = Integer.parseInt(args[0]);
int E = Integer.parseInt(args[1]); Graph G1 = GraphGenerator.eulerianCycle(V, E);
unitTest(G1, "Eulerian cycle"); Graph G2 = GraphGenerator.eulerianPath(V, E);
unitTest(G2, "Eulerian path"); Graph G3 = new Graph(G2);
G3.addEdge(StdRandom.uniform(V), StdRandom.uniform(V));
unitTest(G3, "one random edge added to Eulerian path"); Graph G4 = new Graph(V);
int v4 = StdRandom.uniform(V);
G4.addEdge(v4, v4);
unitTest(G4, "single self loop"); Graph G5 = new Graph(V);
G5.addEdge(StdRandom.uniform(V), StdRandom.uniform(V));
unitTest(G5, "single edge"); Graph G6 = new Graph(V);
unitTest(G6, "empty graph"); Graph G7 = GraphGenerator.simple(V, E);
unitTest(G7, "simple graph");
}
}
● 有向图中寻找欧拉路径,只注释了与欧拉环以及无向图欧拉路径不同的地方
package package01; import java.util.Iterator;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.DigraphGenerator;
import edu.princeton.cs.algs4.Graph;
import edu.princeton.cs.algs4.Digraph;
import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.BreadthFirstPaths; public class class01
{
private Stack<Integer> path = null; public class01(Digraph G)
{
int s = nonIsolatedVertex(G);
if (s == -1) // 没有边
s = 0;
else
{
int deficit = 0; // 统计所有顶点总出度与总入度的差
for (int v = 0; v < G.V(); v++)
{
if (G.outdegree(v) > G.indegree(v)) // 计算 deficit 不能直接加总出度和入度的差
{ // 因为平行边不影响 G.outdegree(v) - G.indegree(v),但会导致不存在欧拉路径
deficit += (G.outdegree(v) - G.indegree(v));
s = v;
}
}
if (deficit > 1) // 差大于 1 则不存在欧拉路径
return;
}
path = new Stack<Integer>();
Iterator<Integer>[] adj = (Iterator<Integer>[]) new Iterator[G.V()];
for (int v = 0; v < G.V(); v++)
adj[v] = G.adj(v).iterator();
Stack<Integer> stack = new Stack<Integer>();
for (stack.push(s); !stack.isEmpty(); )
{
int v = stack.pop();
for (; adj[v].hasNext(); v = adj[v].next())
stack.push(v);
path.push(v);
}
if (path.size() != G.E() + 1)
path = null;
} public Iterable<Integer> path()
{
return path;
} public boolean hasEulerianPath()
{
return path != null;
} private static int nonIsolatedVertex(Digraph G)
{
for (int v = 0; v < G.V(); v++)
{
if (G.outdegree(v) > 0)
return v;
}
return -1;
} private static boolean satisfiesNecessaryAndSufficientConditions(Digraph G)
{
if (G.E() == 0)
return true;
int deficit = 0;
for (int v = 0; v < G.V(); v++)
{
if (G.outdegree(v) > G.indegree(v))
deficit += (G.outdegree(v) - G.indegree(v));
}
if (deficit > 1)
return false;
Graph H = new Graph(G.V());
for (int v = 0; v < G.V(); v++)
{
for (int w : G.adj(v))
H.addEdge(v, w);
}
BreadthFirstPaths bfs = new BreadthFirstPaths(H, nonIsolatedVertex(G));
for (int v = 0; v < G.V(); v++)
{
if (H.degree(v) > 0 && !bfs.hasPathTo(v))
return false;
}
return true;
} private static void unitTest(Digraph G, String description)
{
System.out.printf("\n%s--------------------------------\n", description);
StdOut.print(G);
class01 euler = new class01(G);
System.out.printf("Eulerian path: ");
if (euler.hasEulerianPath())
{
for (int v : euler.path())
System.out.printf(" %d", v);
}
StdOut.println();
} public static void main(String[] args)
{
int V = Integer.parseInt(args[0]);
int E = Integer.parseInt(args[1]); Digraph G1 = DigraphGenerator.eulerianCycle(V, E);
unitTest(G1, "Eulerian cycle"); Digraph G2 = DigraphGenerator.eulerianPath(V, E);
unitTest(G2, "Eulerian path"); Digraph G3 = new Digraph(G2);
G3.addEdge(StdRandom.uniform(V), StdRandom.uniform(V));
unitTest(G3, "one random edge added to Eulerian path"); Digraph G4 = new Digraph(V);
int v4 = StdRandom.uniform(V);
G4.addEdge(v4, v4);
unitTest(G4, "single self loop"); Digraph G5 = new Digraph(V);
G5.addEdge(StdRandom.uniform(V), StdRandom.uniform(V));
unitTest(G5, "single edge"); Digraph G6 = new Digraph(V);
unitTest(G6, "empty digraph"); Digraph G7 = DigraphGenerator.simple(V, E);
unitTest(G7, "simple digraph");
}
}
《算法》第四章部分程序 part 8的更多相关文章
- 《算法》第四章部分程序 part 19
▶ 书中第四章部分程序,包括在加上自己补充的代码,有边权有向图的邻接矩阵,FloydWarshall 算法可能含负环的有边权有向图任意两点之间的最短路径 ● 有边权有向图的邻接矩阵 package p ...
- 《算法》第四章部分程序 part 18
▶ 书中第四章部分程序,包括在加上自己补充的代码,在有权有向图中寻找环,Bellman - Ford 算法求最短路径,套汇算法 ● 在有权有向图中寻找环 package package01; impo ...
- 《算法》第四章部分程序 part 16
▶ 书中第四章部分程序,包括在加上自己补充的代码,Dijkstra 算法求有向 / 无向图最短路径,以及所有顶点对之间的最短路径 ● Dijkstra 算法求有向图最短路径 package packa ...
- 《算法》第四章部分程序 part 15
▶ 书中第四章部分程序,包括在加上自己补充的代码,Kruskal 算法和 Boruvka 算法求最小生成树 ● Kruskal 算法求最小生成树 package package01; import e ...
- 《算法》第四章部分程序 part 14
▶ 书中第四章部分程序,包括在加上自己补充的代码,两种 Prim 算法求最小生成树 ● 简单 Prim 算法求最小生成树 package package01; import edu.princeton ...
- 《算法》第四章部分程序 part 10
▶ 书中第四章部分程序,包括在加上自己补充的代码,包括无向图连通分量,Kosaraju - Sharir 算法.Tarjan 算法.Gabow 算法计算有向图的强连通分量 ● 无向图连通分量 pack ...
- 《算法》第四章部分程序 part 9
▶ 书中第四章部分程序,包括在加上自己补充的代码,两种拓扑排序的方法 ● 拓扑排序 1 package package01; import edu.princeton.cs.algs4.Digraph ...
- 《算法》第四章部分程序 part 17
▶ 书中第四章部分程序,包括在加上自己补充的代码,无环图最短 / 最长路径通用程序,关键路径方法(critical path method)解决任务调度问题 ● 无环图最短 / 最长路径通用程序 pa ...
- 《算法》第四章部分程序 part 13
▶ 书中第四章部分程序,包括在加上自己补充的代码,图的前序.后序和逆后续遍历,以及传递闭包 ● 图的前序.后序和逆后续遍历 package package01; import edu.princeto ...
- 《算法》第四章部分程序 part 12
▶ 书中第四章部分程序,包括在加上自己补充的代码,图的几种补充数据结构,包括无向 / 有向符号图,有权边结构,有边权有向图 ● 无向符号图 package package01; import edu. ...
随机推荐
- CentOS 7.4 初次手记:第二章 CentOS安装步骤
第二章 CentOS安装步骤... 18 第一节 下载... 18 第二节 分区参考... 18 第三节 安装... 19 I Step 1:引导... 19 II Step 2:配置... 20 I ...
- Mysql 性能优化5【重要】数据库结构优化
数据库设计的步骤 我们大多使用mysql 设计三范式 设置时区
- 53题看透java线程
1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成 ...
- Hadoop 新增删除节点
1 新增Data节点 1.1 修改/etc/hosts,增加datanode的ip 1.2 在新增加的节点启动服务 hadoop-daemon.sh start datanode yarn-daemo ...
- problem:vue之数据变更没有触发视图更新问题
前言: 数据变更之后,vue如何渲染dom? 实际场景: 更新数据之后,再设置滚动条的位置为什么设置无效? 为什么将隐藏的元素设置为显示状态之后,读取元素状态读取不到? 改变了对象/数组中的值,页面没 ...
- bzoj 4811: [Ynoi2017]由乃的OJ
树链剖分,用zkw线段树维护每条链两个方向上对每一位的变换情况,由于位数较少,可以用两个unsigned long long表示 #include<cstdio> typedef unsi ...
- 协议无关组播--稀疏模式 PIM-SM
一. 1)PIM-SM 1.PIM-SM转发.加入 PIM-SM适合于接收成员较少的环境.它与DM有何显著的区别?先看PIM-SM转发机制. 转发: 当组播数据到达路由器时,路由器也会去创建转发项.转 ...
- view之自定义控件
转载自:http://blog.163.com/ppy2790@126/blog/static/103242241201382210910473/ 开发自定义控件的步骤: 1.了解View的工作原理 ...
- Android点赞音效播放
/** * 音效播放 */ private SoundPool mPool; /** * 音效id */ private int voiceID; voiceID = initSoundPool(); ...
- 结对编程——paperOne基于java的四则运算 功能改进
项目成员:张金生 张政 由于新的需求,原本使用JSP的实现方式目前改为Java实现,即去除了B/S端. 需求分析: 1.四则运算要满足整数运算.分数运算两种: 2.运算题目随机,并且可以打印题 ...