diff --git a/algs4/algs4.csproj b/algs4/algs4.csproj index 08f4e16..a5f7289 100644 --- a/algs4/algs4.csproj +++ b/algs4/algs4.csproj @@ -54,10 +54,13 @@ + + + diff --git a/algs4/algs4/DigraphGenerator.cs b/algs4/algs4/DigraphGenerator.cs new file mode 100644 index 0000000..ffd1527 --- /dev/null +++ b/algs4/algs4/DigraphGenerator.cs @@ -0,0 +1,528 @@ +using System; +using algs4.stdlib; + +namespace algs4.algs4 +{ + public static class DigraphGenerator + { + private class Edge : IComparable + { + private readonly int _v; + private readonly int _w; + + public Edge(int v, int w) + { + _v = v; + _w = w; + } + 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; + } + } + + /// + /// Returns a random simple digraph containing V vertices and E edges. + /// + /// the number of vertices + /// the number of vertices + /// a random simple digraph on V vertices, containing a total of E edges + public static Digraph Simple(int v, int e) + { + if (e > (long)v * (v - 1)) + { + throw new ArgumentException("Too many edges"); + } + if (e < 0) + { + throw new ArgumentException("Too few edges"); + } + Digraph g = new Digraph(v); + Set set = new Set(); + while (g.E() < e) + { + int vCount = StdRandom.Uniform(v); + int wCount = StdRandom.Uniform(v); + Edge edge = new Edge(vCount, wCount); + if ((vCount != wCount) && !set.Contains(edge)) + { + set.Add(edge); + g.AddEdge(vCount, wCount); + } + } + return g; + } + + /// + /// Returns a random simple digraph on V vertices, with an + /// edge between any two vertices with probability p. This is sometimes + /// referred to as the Erdos-Renyi random digraph model. + /// This implementations takes time propotional to V^2 (even if p is small). + /// + /// the number of vertices + /// the probability of choosing an edge + /// a random simple digraph on V vertices, with an edge between any two vertices with probability p + public static Digraph Simple(int v, double p) + { + if (p < 0.0 || p > 1.0) + { + throw new ArgumentException("Probability must be between 0 and 1"); + } + Digraph g = new Digraph(v); + for (int vertex = 0; vertex < v; vertex++) + { + for (int w = 0; w < v; w++) + { + if (vertex != w) + { + if (StdRandom.Bernoulli(p)) + { + g.AddEdge(vertex, w); + } + } + } + } + return g; + } + + /// + /// Returns the complete digraph on V vertices. + /// + /// the number of vertices + /// the complete digraph on V vertices + public static Digraph Complete(int v) + { + return Simple(v, v * (v - 1)); + } + + /// + /// Returns a random simple DAG containing V vertices and E edges. + /// Note: it is not uniformly selected at random among all such DAGs. + /// + /// the number of vertices + /// the number of vertices + /// a random simple DAG on V vertices, containing a total of E edges + public static Digraph DAG(int v, int e) + { + if (e > (long)v * (v - 1) / 2) + { + throw new ArgumentException("Too many edges"); + } + if (e < 0) + { + throw new ArgumentException("Too few edges"); + } + Digraph g = new Digraph(v); + Set set = new Set(); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + while (g.E() < e) + { + int vCount = StdRandom.Uniform(v); + int wCount = StdRandom.Uniform(v); + Edge edge = new Edge(vCount, wCount); + if ((vCount < wCount) && !set.Contains(edge)) + { + set.Add(edge); + g.AddEdge(vertices[vCount], vertices[wCount]); + } + } + return g; + } + + /// + /// Returns a random tournament digraph on V vertices. A tournament digraph + /// is a DAG in which for every two vertices, there is one directed edge. + /// A tournament is an oriented complete graph. + /// + /// the number of vertices + /// a random tournament digraph on V vertices + public static Digraph Tournament(int v) + { + Digraph g = new Digraph(v); + for (int vertex = 0; vertex < g.V(); vertex++) + { + for (int w = vertex + 1; w < g.V(); w++) + { + if (StdRandom.Bernoulli(0.5)) + { + g.AddEdge(vertex, w); + } + else + { + g.AddEdge(w, vertex); + } + } + } + return g; + } + + /// + /// Returns a random rooted-in DAG on V vertices and E edges. + /// A rooted in-tree is a DAG in which there is a single vertex + /// reachable from every other vertex. + /// The DAG returned is not chosen uniformly at random among all such DAGs. + /// + /// the number of vertices + /// the number of edges + /// a random rooted-in DAG on V vertices and E edges + public static Digraph RootedInDAG(int v, int e) + { + if (e > (long)v * (v - 1) / 2) + { + throw new ArgumentException("Too many edges"); + } + if (e < v - 1) + { + throw new ArgumentException("Too few edges"); + } + Digraph g = new Digraph(v); + Set set = new Set(); + + // fix a topological order + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + + // one edge pointing from each vertex, other than the root = vertices[V-1] + for (int vertex = 0; vertex < v - 1; vertex++) + { + int w = StdRandom.Uniform(vertex + 1, v); + Edge edge = new Edge(vertex, w); + set.Add(edge); + g.AddEdge(vertices[vertex], vertices[w]); + } + + while (g.E() < e) + { + int vCount = StdRandom.Uniform(v); + int wCount = StdRandom.Uniform(v); + Edge edge = new Edge(vCount, wCount); + if ((vCount < wCount) && !set.Contains(edge)) + { + set.Add(edge); + g.AddEdge(vertices[vCount], vertices[wCount]); + } + } + return g; + } + + /// + /// Returns a random rooted-out DAG on V vertices and E edges. + /// A rooted out-tree is a DAG in which every vertex is reachable from a + /// single vertex. + /// The DAG returned is not chosen uniformly at random among all such DAGs. + /// + /// the number of vertices + /// the number of edges + /// a random rooted-out DAG on V vertices and E edges + public static Digraph RootedOutDAG(int v, int e) + { + if (e > (long)v * (v - 1) / 2) + { + throw new ArgumentException("Too many edges"); + } + if (e < v - 1) + { + throw new ArgumentException("Too few edges"); + } + Digraph g = new Digraph(v); + Set set = new Set(); + + // fix a topological order + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + + // one edge pointing from each vertex, other than the root = vertices[V-1] + for (int vertex = 0; vertex < v - 1; vertex++) + { + int wCount = StdRandom.Uniform(vertex + 1, v); + Edge edge = new Edge(wCount, vertex); + set.Add(edge); + g.AddEdge(vertices[wCount], vertices[vertex]); + } + + while (g.E() < e) + { + int vCount = StdRandom.Uniform(v); + int wCount = StdRandom.Uniform(v); + Edge edge = new Edge(wCount, vCount); + if ((vCount < wCount) && !set.Contains(edge)) + { + set.Add(edge); + g.AddEdge(vertices[wCount], vertices[vCount]); + } + } + return g; + } + + /// + /// Returns a random rooted-in tree on V vertices. + /// A rooted in-tree is an oriented tree in which there is a single vertex + /// reachable from every other vertex. + /// The tree returned is not chosen uniformly at random among all such trees. + /// + /// the number of vertices + /// a random rooted-in tree on V vertices + public static Digraph RootedInTree(int v) + { + return RootedInDAG(v, v - 1); + } + + /// + /// Returns a random rooted-out tree on V vertices. A rooted out-tree + /// is an oriented tree in which each vertex is reachable from a single vertex. + /// It is also known as a arborescence or branching. + /// The tree returned is not chosen uniformly at random among all such trees. + /// + /// the number of vertices + /// a random rooted-out tree on V vertices + public static Digraph RootedOutTree(int v) + { + return RootedOutDAG(v, v - 1); + } + + /// + /// Returns a path digraph on V vertices. + /// + /// the number of vertices in the path + /// a digraph that is a directed path on V vertices + public static Digraph Path(int v) + { + Digraph g = new Digraph(v); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + for (int i = 0; i < v - 1; i++) + { + g.AddEdge(vertices[i], vertices[i + 1]); + } + return g; + } + + /// + /// Returns a complete binary tree digraph on V vertices. + /// + /// the number of vertices in the binary tree + /// a digraph that is a complete binary tree on V vertices + public static Digraph BinaryTree(int v) + { + Digraph g = new Digraph(v); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) vertices[i] = i; + StdRandom.Shuffle(vertices); + for (int i = 1; i < v; i++) + { + g.AddEdge(vertices[i], vertices[(i - 1) / 2]); + } + return g; + } + + /// + /// Returns a cycle digraph on V vertices. + /// + /// the number of vertices in the cycle + /// a digraph that is a directed cycle on v vertices + public static Digraph Cycle(int v) + { + Digraph g = new Digraph(v); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + for (int i = 0; i < v - 1; i++) + { + g.AddEdge(vertices[i], vertices[i + 1]); + } + g.AddEdge(vertices[v - 1], vertices[0]); + return g; + } + + /// + /// Returns a random simple digraph on V vertices, E + /// edges and (at least) c strong components. The vertices are randomly + /// assigned int labels between 0 and c-1 (corresponding to + /// strong components). Then, a strong component is creates among the vertices + /// with the same label. Next, random edges (either between two vertices with + /// the same labels or from a vetex with a smaller label to a vertex with a + /// larger label). The number of components will be equal to the number of + /// distinct labels that are assigned to vertices. + /// + /// the number of vertices + /// the number of edges + /// the (maximum) number of strong components + /// a random simple digraph on V vertices and E edges, with (at most) c strong components + public static Digraph Strong(int v, int e, int c) + { + if (c >= v || c <= 0) + { + throw new ArgumentException("Number of components must be between 1 and V"); + } + if (e <= 2 * (v - c)) + { + throw new ArgumentException("Number of edges must be at least 2(V-c)"); + } + if (e > (long)v * (v - 1) / 2) + { + throw new ArgumentException("Too many edges"); + } + + // the digraph + Digraph g = new Digraph(v); + + // edges.Added to G (to avoid duplicate edges) + Set set = new Set(); + + int[] label = new int[v]; + for (int vertex = 0; vertex < v; vertex++) + { + label[vertex] = StdRandom.Uniform(c); + } + + // make all vertices with label c a strong component by + // combining a rooted in-tree and a rooted out-tree + for (int i = 0; i < c; i++) + { + // how many vertices in component c + int count = 0; + for (int vertex = 0; vertex < g.V(); vertex++) + { + if (label[vertex] == i) + { + count++; + } + } + + // if (count == 0) System.err.println("less than desired number of strong components"); + + int[] vertices = new int[count]; + int j = 0; + for (int vertex = 0; vertex < v; vertex++) + { + if (label[vertex] == i) + { + vertices[j++] = vertex; + } + } + StdRandom.Shuffle(vertices); + + // rooted-in tree with root = vertices[count-1] + for (int vertex = 0; vertex < count - 1; vertex++) + { + int w = StdRandom.Uniform(vertex + 1, count); + Edge edge = new Edge(w, vertex); + set.Add(edge); + g.AddEdge(vertices[w], vertices[vertex]); + } + + // rooted-out tree with root = vertices[count-1] + for (int vertex = 0; vertex < count - 1; vertex++) + { + int w = StdRandom.Uniform(vertex + 1, count); + Edge edge = new Edge(vertex, w); + set.Add(edge); + g.AddEdge(vertices[vertex], vertices[w]); + } + } + + while (g.E() < e) + { + int vCount = StdRandom.Uniform(v); + int wCount = StdRandom.Uniform(v); + Edge edge = new Edge(vCount, wCount); + if (!set.Contains(edge) && vCount != wCount && label[vCount] <= label[wCount]) + { + set.Add(edge); + g.AddEdge(vCount, wCount); + } + } + + return g; + } + + /// + /// Unit tests the DigraphGenerator library. + /// + /// + public static void RunMain(string[] args) + { + int v = int.Parse(args[0]); + int e = int.Parse(args[1]); + Console.WriteLine("complete graph"); + Console.WriteLine(Complete(v)); + Console.WriteLine(); + + Console.WriteLine("simple"); + Console.WriteLine(Simple(v, e)); + Console.WriteLine(); + + Console.WriteLine("path"); + Console.WriteLine(Path(v)); + Console.WriteLine(); + + Console.WriteLine("cycle"); + Console.WriteLine(Cycle(v)); + Console.WriteLine(); + + Console.WriteLine("binary tree"); + Console.WriteLine(BinaryTree(v)); + Console.WriteLine(); + + Console.WriteLine("tournament"); + Console.WriteLine(Tournament(v)); + Console.WriteLine(); + + Console.WriteLine("DAG"); + Console.WriteLine(DAG(v, e)); + Console.WriteLine(); + + Console.WriteLine("rooted-in DAG"); + Console.WriteLine(RootedInDAG(v, e)); + Console.WriteLine(); + + Console.WriteLine("rooted-out DAG"); + Console.WriteLine(RootedOutDAG(v, e)); + Console.WriteLine(); + + Console.WriteLine("rooted-in tree"); + Console.WriteLine(RootedInTree(v)); + Console.WriteLine(); + + Console.WriteLine("rooted-out DAG"); + Console.WriteLine(RootedOutTree(v)); + Console.WriteLine(); + } + } +} diff --git a/algs4/algs4/Graph.cs b/algs4/algs4/Graph.cs new file mode 100644 index 0000000..c232f8f --- /dev/null +++ b/algs4/algs4/Graph.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Text; +using algs4.stdlib; + +namespace algs4.algs4 +{ + public class Graph + { + private readonly int _v; + private int _e; + private readonly Bag[] _adj; + + /// + /// Initializes an empty graph with V vertices and 0 edges. + /// + /// the number of vertices + public Graph(int v) + { + if (v < 0) + { + throw new ArgumentException("Number of vertices must be nonnegative"); + } + _v = v; + _e = 0; + _adj = new Bag[v]; + for (int vertex = 0; vertex < v; vertex++) + { + _adj[vertex] = new Bag(); + } + } + + /// + /// Initializes a graph from an input stream. + /// The format is the number of vertices V, + /// followed by the number of edges E, + /// followed by E pairs of vertices, with each entry separated by whitespace. + /// + /// the input stream + public Graph(In input) + : this(input.ReadInt()) + { + + int e = input.ReadInt(); + if (e < 0) + { + throw new ArgumentException("Number of edges must be nonnegative"); + } + for (int i = 0; i < e; i++) + { + int v = input.ReadInt(); + int w = input.ReadInt(); + AddEdge(v, w); + } + } + + /// + /// Initializes a new graph that is a deep copy of G. + /// + /// the graph to copy + public Graph(Graph g) + : this(g.V()) + { + _e = g.E(); + for (int v = 0; v < g.V(); v++) + { + // reverse so that adjacency list is in same order as original + Stack reverse = new Stack(); + foreach (int w in g._adj[v]) + { + reverse.Push(w); + } + foreach (int w in reverse) + { + _adj[v].Add(w); + } + } + } + + /// + /// Returns the number of vertices in the graph. + /// + /// the number of vertices in the graph + public int V() + { + return _v; + } + + /// + /// Returns the number of edges in the graph. + /// + /// the number of edges in the graph + public int E() + { + return _e; + } + + /// + /// Throw an IndexOutOfBoundsException unless 0 <= v < _v + /// + /// + private void ValidateVertex(int v) + { + if (v < 0 || v >= _v) + { + throw new IndexOutOfRangeException("vertex " + v + " is not between 0 and " + (_v - 1)); + } + } + + /// + /// Adds the undirected edge v-w to the graph. + /// + /// one vertex in the edge + /// the other vertex in the edge + public void AddEdge(int v, int w) + { + ValidateVertex(v); + ValidateVertex(w); + _e++; + _adj[v].Add(w); + _adj[w].Add(v); + } + + /// + /// Returns the vertices adjacent to vertex v. + /// + /// the vertex + /// the vertices adjacent to vertex v as an Iterable + public IEnumerable Adj(int v) + { + ValidateVertex(v); + return _adj[v]; + } + + /// + /// Returns the degree of vertex v. + /// + /// the vertex + /// the degree of vertex v + public int Degree(int v) + { + ValidateVertex(v); + return _adj[v].Size(); + } + + /// + /// Returns a string representation of the graph. + /// This method takes time proportional to E + V. + /// + /// the number of vertices V, followed by the number of edges E, followed by the V adjacency lists + public override string ToString() + { + StringBuilder s = new StringBuilder(); + string newline = Environment.NewLine; + s.Append(_v + " vertices, " + _e + " edges " + newline); + for (int v = 0; v < _v; v++) + { + s.Append(v + ": "); + foreach (int w in _adj[v]) + { + s.Append(w + " "); + } + s.Append(newline); + } + return s.ToString(); + } + + /// + /// Unit tests the Graph data type. + /// + /// + public static void RunMain(string[] args) + { + In input = new In(args[0]); + Graph g = new Graph(input); + StdOut.PrintLn(g); + } + } +} diff --git a/algs4/algs4/GraphGenerator.cs b/algs4/algs4/GraphGenerator.cs new file mode 100644 index 0000000..c1f6f06 --- /dev/null +++ b/algs4/algs4/GraphGenerator.cs @@ -0,0 +1,496 @@ +using System; +using algs4.stdlib; + +namespace algs4.algs4 +{ + public class GraphGenerator + { + private class Edge : IComparable + { + private readonly int _v; + private readonly int _w; + + public Edge(int v, int w) + { + if (v < w) + { + _v = v; + _w = w; + } + else + { + _v = w; + _w = v; + } + } + + 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; + } + } + + /// + /// Returns a random simple graph containing V vertices and E edges. + /// + /// the number of vertices + /// the number of edges + /// a random simple graph on V vertices, containing a total of E edges + public static Graph Simple(int v, int e) + { + if (e > (long)v * (v - 1) / 2) + { + throw new ArgumentException("Too many edges"); + } + if (e < 0) + { + throw new ArgumentException("Too few edges"); + } + Graph g = new Graph(v); + Set set = new Set(); + while (g.E() < e) + { + int vCount = StdRandom.Uniform(v); + int wCount = StdRandom.Uniform(v); + Edge edge = new Edge(vCount, wCount); + if ((vCount != wCount) && !set.Contains(edge)) + { + set.Add(edge); + g.AddEdge(vCount, wCount); + } + } + return g; + } + + /// + /// Returns a random simple graph on V vertices, with an + /// edge between any two vertices with probability p. This is sometimes + /// referred to as the Erdos-Renyi random graph model. + /// + /// the number of vertices + /// the probability of choosing an edge + /// a random simple graph on V vertices, with an edge between any two vertices with probability p + public static Graph Simple(int v, double p) + { + if (p < 0.0 || p > 1.0) + { + throw new ArgumentException("Probability must be between 0 and 1"); + } + Graph g = new Graph(v); + for (int vertex = 0; vertex < v; vertex++) + { + for (int w = vertex + 1; w < v; w++) + { + if (StdRandom.Bernoulli(p)) + { + g.AddEdge(vertex, w); + } + } + } + return g; + } + + /// + /// Returns the complete graph on V vertices. + /// + /// the number of vertices + /// the complete graph on V vertices + public static Graph Complete(int v) + { + return Simple(v, 1.0); + } + + /// + /// Returns a complete bipartite graph on V1 and V2 vertices. + /// + /// the number of vertices in one partition + /// the number of vertices in the other partition + /// a complete bipartite graph on V1 and V2 vertices + public static Graph CompleteBipartite(int v1, int v2) + { + return Bipartite(v1, v2, v1 * v2); + } + + /// + /// Returns a random simple bipartite graph on V1 and V2 vertices + /// with E edges. + /// + /// the number of vertices in one partition + /// the number of vertices in the other partition + /// the number of edges + /// a random simple bipartite graph on V1 and V2 vertices, containing a total of E edges + public static Graph Bipartite(int v1, int v2, int e) + { + if (e > (long)v1 * v2) + { + throw new ArgumentException("Too many edges"); + } + if (e < 0) + { + throw new ArgumentException("Too few edges"); + } + Graph g = new Graph(v1 + v2); + + int[] vertices = new int[v1 + v2]; + for (int i = 0; i < v1 + v2; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + + Set set = new Set(); + while (g.E() < e) + { + int i = StdRandom.Uniform(v1); + int j = v1 + StdRandom.Uniform(v2); + Edge edge = new Edge(vertices[i], vertices[j]); + if (!set.Contains(edge)) + { + set.Add(edge); + g.AddEdge(vertices[i], vertices[j]); + } + } + return g; + } + + /// + /// Returns a random simple bipartite graph on V1 and V2 vertices, + /// containing each possible edge with probability p. + /// + /// the number of vertices in one partition + /// the number of vertices in the other partition + /// the probability that the graph contains an edge with one endpoint in either side + /// a random simple bipartite graph on V1 and V2 vertices, containing each possible edge with probability p + public static Graph Bipartite(int v1, int v2, double p) + { + if (p < 0.0 || p > 1.0) + { + throw new ArgumentException("Probability must be between 0 and 1"); + } + int[] vertices = new int[v1 + v2]; + for (int i = 0; i < v1 + v2; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + Graph g = new Graph(v1 + v2); + for (int i = 0; i < v1; i++) + { + for (int j = 0; j < v2; j++) + { + if (StdRandom.Bernoulli(p)) + { + g.AddEdge(vertices[i], vertices[v1 + j]); + } + } + } + return g; + } + + /// + /// Returns a path graph on V vertices. + /// + /// the number of vertices in the path + /// a path graph on V vertices + public static Graph Path(int v) + { + Graph g = new Graph(v); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + for (int i = 0; i < v - 1; i++) + { + g.AddEdge(vertices[i], vertices[i + 1]); + } + return g; + } + + /// + /// Returns a complete binary tree graph on V vertices. + /// + /// the number of vertices in the binary tree + /// a complete binary tree graph on V vertices + public static Graph BinaryTree(int v) + { + Graph g = new Graph(v); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + for (int i = 1; i < v; i++) + { + g.AddEdge(vertices[i], vertices[(i - 1) / 2]); + } + return g; + } + + /// + /// Returns a cycle graph on V vertices. + /// + /// the number of vertices in the cycle + /// a cycle graph on V vertices + public static Graph Cycle(int v) + { + Graph g = new Graph(v); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + for (int i = 0; i < v - 1; i++) + { + g.AddEdge(vertices[i], vertices[i + 1]); + } + g.AddEdge(vertices[v - 1], vertices[0]); + return g; + } + + /// + /// Returns a wheel graph on V vertices. + /// + /// the number of vertices in the wheel + /// a wheel graph on V vertices: a single vertex connected to every vertex in a cycle on V-1 vertices + public static Graph Wheel(int v) + { + if (v <= 1) + { + throw new ArgumentException("Number of vertices must be at least 2"); + } + Graph g = new Graph(v); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + + // simple cycle on V-1 vertices + for (int i = 1; i < v - 1; i++) + { + g.AddEdge(vertices[i], vertices[i + 1]); + } + g.AddEdge(vertices[v - 1], vertices[1]); + + // connect vertices[0] to every vertex on cycle + for (int i = 1; i < v; i++) + { + g.AddEdge(vertices[0], vertices[i]); + } + + return g; + } + + /// + /// Returns a star graph on V vertices. + /// + /// the number of vertices in the star + /// a star graph on V vertices: a single vertex connected to every other vertex + public static Graph Star(int v) + { + if (v <= 0) + { + throw new ArgumentException("Number of vertices must be at least 1"); + } + Graph g = new Graph(v); + int[] vertices = new int[v]; + for (int i = 0; i < v; i++) + { + vertices[i] = i; + } + StdRandom.Shuffle(vertices); + + // connect vertices[0] to every other vertex + for (int i = 1; i < v; i++) + { + g.AddEdge(vertices[0], vertices[i]); + } + + return g; + } + + /// + /// Returns a uniformly random k-regular graph on V vertices + /// (not necessarily simple). The graph is simple with probability only about e^(-k^2/4), + /// which is tiny when k = 14. + /// + /// the number of vertices in the graph + /// + /// a uniformly random k-regular graph on V vertices. + public static Graph Regular(int v, int k) + { + if (v * k % 2 != 0) + { + throw new ArgumentException("Number of vertices * k must be even"); + } + Graph g = new Graph(v); + + // create k copies of each vertex + int[] vertices = new int[v * k]; + for (int vertex = 0; vertex < v; vertex++) + { + for (int j = 0; j < k; j++) + { + vertices[vertex + v * j] = vertex; + } + } + + // pick a random perfect matching + StdRandom.Shuffle(vertices); + for (int i = 0; i < v * k / 2; i++) + { + g.AddEdge(vertices[2 * i], vertices[2 * i + 1]); + } + return g; + } + + /// + /// Returns a uniformly random tree on V vertices. + /// This algorithm uses a Prufer sequence and takes time proportional to V log V. + /// http://www.proofwiki.org/wiki/Labeled_Tree_from_Prüfer_Sequence + /// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.36.6484&rep=rep1&type=pdf + /// + /// the number of vertices in the tree + /// a uniformly random tree on V vertices + public static Graph Tree(int v) + { + Graph g = new Graph(v); + + // special case + if (v == 1) + { + return g; + } + + // Cayley's theorem: there are V^(V-2) labeled trees on V vertices + // Prufer sequence: sequence of V-2 values between 0 and V-1 + // Prufer's proof of Cayley's theorem: Prufer sequences are in 1-1 + // with labeled trees on V vertices + int[] prufer = new int[v - 2]; + for (int i = 0; i < v - 2; i++) + { + prufer[i] = StdRandom.Uniform(v); + } + + // degree of vertex v = 1 + number of times it appers in Prufer sequence + int[] degree = new int[v]; + for (int vertex = 0; vertex < v; vertex++) + { + degree[vertex] = 1; + } + for (int i = 0; i < v - 2; i++) + { + degree[prufer[i]]++; + } + + // pq contains all vertices of degree 1 + MinPQ pq = new MinPQ(); + for (int vertex = 0; vertex < v; vertex++) + { + if (degree[vertex] == 1) pq.Insert(vertex); + } + + // repeatedly DelMin() degree 1 vertex that has the minimum index + for (int i = 0; i < v - 2; i++) + { + int vertex = pq.DelMin(); + g.AddEdge(vertex, prufer[i]); + degree[vertex]--; + degree[prufer[i]]--; + if (degree[prufer[i]] == 1) + { + pq.Insert(prufer[i]); + } + } + g.AddEdge(pq.DelMin(), pq.DelMin()); + return g; + } + + /// + /// Unit tests the GraphGenerator library. + /// + /// + public static void RunMain(string[] args) + { + int v = int.Parse(args[0]); + int e = int.Parse(args[1]); + int v1 = v / 2; + int v2 = v - v1; + + StdOut.PrintLn("complete graph"); + StdOut.PrintLn(Complete(v)); + StdOut.PrintLn(); + + StdOut.PrintLn("simple"); + StdOut.PrintLn(Simple(v, e)); + StdOut.PrintLn(); + + StdOut.PrintLn("Erdos-Renyi"); + double p = e / (v * (v - 1) / 2.0); + StdOut.PrintLn(Simple(v, p)); + StdOut.PrintLn(); + + StdOut.PrintLn("complete bipartite"); + StdOut.PrintLn(CompleteBipartite(v1, v2)); + StdOut.PrintLn(); + + StdOut.PrintLn("bipartite"); + StdOut.PrintLn(Bipartite(v1, v2, e)); + StdOut.PrintLn(); + + StdOut.PrintLn("Erdos Renyi bipartite"); + double q = (double)e / (v1 * v2); + StdOut.PrintLn(Bipartite(v1, v2, q)); + StdOut.PrintLn(); + + StdOut.PrintLn("path"); + StdOut.PrintLn(Path(v)); + StdOut.PrintLn(); + + StdOut.PrintLn("cycle"); + StdOut.PrintLn(Cycle(v)); + StdOut.PrintLn(); + + StdOut.PrintLn("binary tree"); + StdOut.PrintLn(BinaryTree(v)); + StdOut.PrintLn(); + + StdOut.PrintLn("tree"); + StdOut.PrintLn(Tree(v)); + StdOut.PrintLn(); + + StdOut.PrintLn("4-regular"); + StdOut.PrintLn(Regular(v, 4)); + StdOut.PrintLn(); + + StdOut.PrintLn("star"); + StdOut.PrintLn(Star(v)); + StdOut.PrintLn(); + + StdOut.PrintLn("wheel"); + StdOut.PrintLn(Wheel(v)); + StdOut.PrintLn(); + } + } +}