《算法》第四章部分程序 part 3
▶ 书中第四章部分程序,加上自己补充的代码,随机生成各类有向图
● 随机生成有向图
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的更多相关文章
- 《算法》第四章部分程序 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. ...
随机推荐
- Opencv 视频保存为图像
// 视频存为图片.cpp : 定义控制台应用程序的入口点. // /*================================================================ ...
- Ubuntu 安装以及web服务器配置
1.安装实在没必要说,连系统都装不了,干脆下岗算了 2.Apache2 安装 //安装 sudo apt-get install apache2 Apache安装完成后,默认的网站根目录是" ...
- 移动互联网终端的touch事件,touchstart, touchend, touchmove 很棒的文章
转载请注明: 转载自WEB前端开发(www.css119.com)-关注常见的WEB前端开发问题.最新的WEB前端开发技术(webApp开发.移动网站开发).最好的WEB前端开发工具和最全的WEB前端 ...
- linux mongodb 及php-mongo扩展安装
安装背景 php7.2.5 ubuntu18.04.1 MongoDb 安装 sudo apt-get install mongodb MongoDb的php扩展 sudo apt-get i ...
- vagrant 安装笔记
本文档的编写参考慕课网视频教程,感谢慕课网提供的免费教程 http://www.imooc.com/learn/805 搭建一个环境,不需要重复配置,直接利用vagrant复制就可以了 https:/ ...
- git add , git commit 添加错文件 撤销
1. git add 添加 多余文件 这样的错误是由于, 有的时候 可能 git add . (空格+ 点) 表示当前目录所有文件,不小心就会提交其他文件 git add 如果添加了错误的文件的话 撤 ...
- phoenix psqlline输入命令无法删除问题解决技巧
一.引言: phoenix psqlline使用过程中,使用CRT客户端,命令输入后无法删除,想起曾经处理HBaseShell输入后无法删除的解决办法,尝试了一下,居然有效,还是分享给大家把. 二.操 ...
- Tomacat 配置
server.xml文件中元素: 1.<Service name="Catalina"> 这个元素相当于IIS的一个网站.该元素可有多个.每个元素会根据名字在conf文 ...
- 1049.(*) Counting Ones
题意:题目大意:给出一个数字n,求1~n的所有数字里面出现1的个数 思路:转自(柳婼 の blog)遍历数字的低位到高位,设now为当前位的数字,left为now左边的所有数字构成的数字,right是 ...
- Kubernetes DNS服务配置案例
首先创建DNS服务的RC配置文件skydns-rc.yaml apiVersion: v1 kind: ReplicationController metadata: name: kube-dns-v ...