▶ 书中第四章部分程序,加上自己补充的代码,随机生成各类有向图

● 随机生成有向图

 package package01;

 import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Digraph; // 多了有向图,少了集合
import edu.princeton.cs.algs4.SET;
import edu.princeton.cs.algs4.StdRandom; public class class01
{
private static final class Edge implements Comparable<Edge>
{
private final int v;
private final int w; private Edge(int v1, int v2)
{
if (v1 < v2)
{
v = v1;
w = v2;
}
else
{
v = v2;
w = v1;
}
} public int compareTo(Edge that)
{
if (v < that.v)
return -1;
if (v > that.v)
return +1;
if (w < that.w)
return -1;
if (w > that.w)
return +1;
return 0;
}
} private class01() {} public static Digraph simple(int V, int E)
{
if (E < 0 || E >(long) V*(V - 1) / 2)
throw new IllegalArgumentException("\n<simple> E < 0 || E > V(V-1)/2.\n");
Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>();
for (; G.E() < E;)
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
Edge e = new Edge(v, w);
if ((v != w) && !set.contains(e))
{
set.add(e);
G.addEdge(v, w);
}
}
return G;
} public static Digraph simple(int V, double p)
{
if (p < 0.0 || p > 1.0)
throw new IllegalArgumentException("\n<simple> p < 0.0 || p > 1.0.\n");
Digraph G = new Digraph(V);
for (int v = 0; v < V; v++)
{
for (int w = 0; w < V; w++) // 从0 开始
{
if (v != w && StdRandom.bernoulli(p)) // 去掉自环
G.addEdge(v, w);
}
}
return G;
} public static Digraph complete(int V)
{
return simple(V, 1.0);
} public static Digraph dag(int V, int E) //(非均匀地)生成指定定点数和边数的有向无环图(Directed Acyclic Graph)
{
if (E < 0 || E >(long) V*(V - 1) / 2)
throw new IllegalArgumentException("\n<dag> E < 0 || E > V1*V2.\n");
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>();
for (; G.E() < E;)
{
int i = StdRandom.uniform(V);
int j = StdRandom.uniform(V);
Edge e = new Edge(i, j);
if (i < j && !set.contains(e)) // 限定从索引较小的顶点指向索引较大的顶点
{
set.add(e);
G.addEdge(vertices[i], vertices[j]);
}
}
return G;
} public static Digraph tournament(int V) // 生成竞赛图(任意两顶点间有一条有向边)
{
Digraph G = new Digraph(V);
for (int v = 0; v < G.V(); v++)
{
for (int w = v + 1; w < G.V(); w++)
{
if (StdRandom.bernoulli(0.5))
G.addEdge(v, w);
else
G.addEdge(w, v);
}
}
return G;
} public static Digraph rootedInDAG(int V, int E) // 生成有入根 DAG 图(所有链有共同的终点)
{
if (E < V - 1 || E >(long) V*(V - 1) / 2)
throw new IllegalArgumentException("\n<rootedInDAG> E < 0 || E > V1*V2.\n");
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>();
for (int v = 0; v < V - 1; v++) // 每个点连接到索引更靠后的一个顶点上,保证每条链都收敛到最后一个顶点
{
int w = StdRandom.uniform(v + 1, V);
Edge e = new Edge(v, w);
set.add(e);
G.addEdge(vertices[v], vertices[w]);
}
for (; G.E() < E;) // 按靠后规则添加剩余的的边
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
Edge e = new Edge(v, w);
if ((v < w) && !set.contains(e))
{
set.add(e);
G.addEdge(vertices[v], vertices[w]);
}
}
return G;
} public static Digraph rootedOutDAG(int V, int E) // 生成有出根 DAG 图(所有链有相同的起点)
{
if (E < V - 1 || E >(long) V*(V - 1) / 2)
throw new IllegalArgumentException("\n<rootedOutDAG> E < 0 || E > V1*V2.\n");
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>();
for (int v = 0; v < V - 1; v++)
{
int w = StdRandom.uniform(v + 1, V);
Edge e = new Edge(w, v); // 就是把 rootedInDAG 中出现 (v,w) 的地方全部换成 (v,w) 即可
set.add(e);
G.addEdge(vertices[w], vertices[v]); //换
}
for (; G.E() < E;)
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
Edge e = new Edge(w, v); // 换
if ((v < w) && !set.contains(e))
{
set.add(e);
G.addEdge(vertices[w], vertices[v]); // 换
}
}
return G;
} public static Digraph rootedInTree(int V) // 生成有入根树,在 rootedInDAG 的基础上限定了边数
{
return rootedInDAG(V, V - 1);
} public static Digraph rootedOutTree(int V) // 生成有出根树,在 rootedOutDAG 的基础上限定了边数
{
return rootedOutDAG(V, V - 1);
} public static Digraph path(int V) // 路径图,同无向版本
{
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
for (int i = 0; i < V - 1; i++)
G.addEdge(vertices[i], vertices[i + 1]);
return G;
} public static Digraph binaryTree(int V) // 二叉树,同无向版本
{
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
for (int i = 1; i < V; i++)
G.addEdge(vertices[i], vertices[(i - 1) / 2]);
return G;
} public static Digraph cycle(int V) // 环,同无向版本
{
int[] vertices = new int[V];
for (int i = 0; i < V; i++)
vertices[i] = i;
StdRandom.shuffle(vertices);
Digraph G = new Digraph(V);
for (int i = 0; i < V - 1; i++)
G.addEdge(vertices[i], vertices[i + 1]);
G.addEdge(vertices[V - 1], vertices[0]);
return G;
} public static Digraph eulerianCycle(int V, int E) // 欧拉回路,同无向版本
{
if (E <= 0 || V <= 0)
throw new IllegalArgumentException("\n<eulerianCycle> E <= 0 || V <= 0.\n");
int[] node = new int[E];
for (int i = 0; i < E; i++)
node[i] = StdRandom.uniform(V);
Digraph G = new Digraph(V);
for (int i = 0; i < E - 1; i++)
G.addEdge(node[i], node[i + 1]);
G.addEdge(node[E - 1], node[0]);
return G;
} public static Digraph eulerianPath(int V, int E) // 欧拉路径,同无向版本
{
if (E <= 0 || V <= 0)
throw new IllegalArgumentException("\n<eulerianPath> E <= 0 || V <= 0.\n");
int[] node = new int[E + 1];
for (int i = 0; i < E + 1; i++)
node[i] = StdRandom.uniform(V);
Digraph G = new Digraph(V);
for (int i = 0; i < E; i++)
G.addEdge(node[i], node[i + 1]);
return G;
} public static Digraph strong(int V, int E, int c) // 生成指定定点数、边数、强连通分量上限数的有向图
{
if (E <= 2 * (V - c) || E >(long) V*(V - 1) / 2 || c >= V || c <= 0)
throw new IllegalArgumentException("\n<strong> E <= 2 * (V - c) || E > (long) V*(V - 1) / 2 || c >= V || c <= 0.\n"); Digraph G = new Digraph(V);
SET<Edge> set = new SET<Edge>(); int[] label = new int[V]; // 给每个顶点一个连通分量的标号
for (int v = 0; v < V; v++)
label[v] = StdRandom.uniform(c);
for (int i = 0; i < c; i++) // 遍历每个分量,分别生成强连通图
{ // 原理是每个分量中挑一个根点,生成关于该点的入根树和出根树,则分量内所有顶点能以该根点为中继进行连通
int count = 0; // 该分量的顶点数
for (int v = 0; v < G.V(); v++)
{
if (label[v] == i)
count++;
}
int[] node = new int[count]; // 在 count 范围内用乱序数组生成子图
int j = 0;
for (int v = 0; v < V; v++) // 选出标号为 i 的所有顶点的编号
{
if (label[v] == i)
node[j++] = v;
}
StdRandom.shuffle(node);
for (int v = 0; v < count - 1; v++) // 生成一棵有入根树,根为 node[count-1]
{
int w = StdRandom.uniform(v + 1, count);
Edge e = new Edge(w, v);
set.add(e);
G.addEdge(node[w], node[v]);
}
for (int v = 0; v < count - 1; v++) // 生成一棵有出根树,根为 node[count-1]
{
int w = StdRandom.uniform(v + 1, count);
Edge e = new Edge(v, w);
set.add(e);
G.addEdge(node[v], node[w]);
}
} for (; G.E() < E;) // 添加剩余边
{
int v = StdRandom.uniform(V);
int w = StdRandom.uniform(V);
Edge e = new Edge(v, w);
if (!set.contains(e) && v != w && label[v] <= label[w]) // 限制顶点的索引范围,防止出现环
{
set.add(e);
G.addEdge(v, w);
}
}
return G;
} public static void main(String[] args)
{
int V = Integer.parseInt(args[0]);
int E = Integer.parseInt(args[1]); StdOut.println("simple");
StdOut.println(simple(V, E)); StdOut.println("Erdos-Renyi");
double p = (double)E / (V*(V - 1) / 2.0);
StdOut.println(simple(V, p)); StdOut.println("complete graph");
StdOut.println(complete(V)); StdOut.println("DAG");
StdOut.println(dag(V, E)); StdOut.println("tournament");
StdOut.println(tournament(V)); StdOut.println("rooted-in DAG");
StdOut.println(rootedInDAG(V, E)); StdOut.println("rooted-out DAG");
StdOut.println(rootedOutDAG(V, E)); StdOut.println("rooted-in tree");
StdOut.println(rootedInTree(V)); StdOut.println("rooted-out DAG");
StdOut.println(rootedOutTree(V)); StdOut.println("path");
StdOut.println(path(V)); StdOut.println("binary tree");
StdOut.println(binaryTree(V)); StdOut.println("cycle");
StdOut.println(cycle(V)); StdOut.println("eulierian cycle");
StdOut.println(eulerianCycle(V, E)); StdOut.println("eulierian path");
StdOut.println(eulerianPath(V, E)); StdOut.println("strong");
StdOut.println(strong(V, E, 4));
}
}

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

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

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

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

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

  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 10

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

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

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

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

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

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

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

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

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

随机推荐

  1. elasticsearch 常用命令(一)

    索引 搜索 mapping 分词器 1.创建索引 http://192.168.65.131:9200/smartom_index?pretty 2.查看索引: http://192.168.65.1 ...

  2. Composer的学习

    来自http://blog.sina.com.cn/s/blog_6262a50e0101b5ut.html 简介 composer是PHP中的一个依赖关系管理工具.只要(按指定格式)声明项目所依赖的 ...

  3. Winfrom DataGridView中使用Tooltip

    第一步:添加DataGridView.Tooltip控件,略 第二步:设置ToolTip 相关属性,略,参考下图 第三步:DataGridView 添加 CellMouseEnter.CellMous ...

  4. IIS7.0 下使用Intelligencia.UrlRewriter时Session为空问题

    背景 新年伊始,本人的开发环境由Windows Server 2003 +IIS 6 升级成了 Windows Server 2008 +IIS 7,之后便着手参加新项目的开发.项目开发后期测试过程中 ...

  5. 【java】之深入理解JVM

    JVM规范定义的标准结构如下: 以上结构是JVM标准规范中定义的,但各厂家在实现时不一定会完全遵守, 1.JVM负责加载class文件并执行,因此,首先要掌握的是JDK如何将Java代码编译成clas ...

  6. Boost--variant (C++中的union)

    union联合体类型的问题 只能用于内部类型,这使得union在C++中几乎没有用 所以boost提供了variant,相当于是C++中的union #include "boost/vari ...

  7. 流媒体技术笔记(DarwinStreamingServer相关)

    简介 Darwin Streaming Server简称DSS.DSS是Apple公司提供的开源实时流媒体播放服务器程序.整个程序使用C++编写,在设计上遵循高性能,简单,模块化等程序设计原则,务求做 ...

  8. DB2 Rename SQL0108N错误

    今天DB2 Rename的时候遇到了“SQL0108N ‘表名’名称的限定符数是错误的. 语句如下: db2 rename tableA to tableB 异常: SQL0108N The name ...

  9. kafka服务自动关闭

    解决方法: kafka启动的时候添加守护进程 bin/kafka-server-start.sh -daemon ./config/server.properties & 问题原因: 待补充. ...

  10. python之路——3

    王二学习python的笔记以及记录,如有雷同,那也没事,欢迎交流,wx:wyb199594 复习 1. 格式化输出 %s %d %%2. 编码 ASCII码——unicode万国码——utf-8(1个 ...