Indicates the data type of an undirected graph.
Recently I have been reading algorithms (version 4th) by Robert Sedgewick and Kevin Wayne:
This book chapter 1 Section 4th discusses undirected graphs. below is the undirected graph API (English Version 1st page ):
For non-dense undirected graphs, the standard representation uses an adjacent table to store all adjacent vertices of an undirected graph in a linked list pointed to by the corresponding elements of the vertex. All vertices are stored in an array. Using this array, you can quickly access the list of adjacent vertices of a given vertex. The following is an example of a non-dense undirected graph (525th pp ):
The implementation performance of this Graph has the following features:
- The used space is proportional to V + E.
- The time required to add an edge is a constant.
- The time required to traverse all adjacent vertices of vertex v is proportional to the degree of v (the time required to process each adjacent vertex is a constant)
For these operations, such features are already optimal and can meet the needs of graph processing applications.
Java program
The following is the Graph. java program (English Version 526th page ):
1 public class Graph 2 { 3 private final int V; // number of vertices 4 private int E; // number of edges 5 private Bag<Integer>[] adj; // adjacency lists 6 7 public Graph(int V) 8 { 9 this.V = V; this.E = 0;10 adj = (Bag<Integer>[]) new Bag[V]; // Create array of lists.11 for (int v = 0; v < V; v++) // Initialize all lists12 adj[v] = new Bag<Integer>(); // to empty.13 }14 15 public Graph(In in)16 {17 this(in.readInt()); // Read V and construct this graph.18 int E = in.readInt(); // Read E.19 for (int i = 0; i < E; i++)20 { // A an edge.21 int v = in.readInt(); // Read a vertex,22 int w = in.readInt(); // read another vertex,23 addEdge(v, w); // and add edge connecting them.24 }25 }26 27 public int V() { return V; }28 public int E() { return E; }29 30 public void addEdge(int v, int w)31 {32 adj[v].add(w); // Add w to v's list.33 adj[w].add(v); // Add v to w's list.34 E++;35 }36 37 public Iterable<Integer> adj(int v)38 { return adj[v]; }39 40 public String toString()41 {42 StringBuilder s = new StringBuilder();43 String NEWLINE = System.getProperty("line.separator");44 s.append(V + " vertices, " + E + " edges" + NEWLINE);45 for (int v = 0; v < V; v++)46 {47 s.append(v + ": ");48 for (int w : adj[v]) s.append(w + " ");49 s.append(NEWLINE);50 }51 return s.toString();52 }53 54 public static void main(String[] args)55 {56 Graph G = new Graph(new In(args[0]));57 StdOut.println(G);58 }59 }
In the above program:
- The number of vertices in the undirected graph is V. The value cannot be modified after initialization in the constructor.
- The number of edges in the undirected graph is E in the field in the row 4th.
- The field in the row 5th indicates the list of the joined list of the undirected graph.
- The Graph constructor of rows 7th to 13 creates an undirected Graph with V vertices but no edges.
- In row 10th, an array of the adjacent tables is created, and each vertex corresponds to an array. Its element is the adjacent table of the vertex, which is implemented using the Bag abstract data type.
- For the Bag data type, see section 4th of algorithm (version 1.3). This data type allows us to add new Edges Within a constant time or traverse all adjacent vertices of any vertex.
- Due to the inherent disadvantage of the Java language, you cannot create a Generic Array. Therefore, you can only create a common array in row 10th and then forcibly convert it to a generic array. This leads to warnings during compilation.
- Due to the inherent disadvantage of the Java language, the generic parameter type cannot be the original data type, so the generic parameter types of rows 5th, 10, 12, and 37 are Integer rather than int. This causes some performance losses.
- The constructor of rows 15th to 25 generates an undirected graph from the input stream. The content of the input stream is the number of vertices V, the number of edges E, and the vertex of each edge. For an example of the input stream, see tinyG.txt in the introduction. For the In type of the input stream, see section 4th of algorithm 1.1.
- The addEdge method of rows 30th to 35 adds an edge connecting v and w. The method is to add w to the v adjacent table and add v to the w adjacent table. Therefore, each edge in the data structure appears twice.
- The toString method of rows 40th to 52 returns the representation of the undirected graph's adjacent table. First, the number of vertices V and the number of edges E, and then the adjacent table of each vertex.
- The main of lines 54th to 58 is the test case. It obtains the name of the input stream from the command line parameters.
- The first line constructs an undirected graph from the input stream.
- Line 3 (implicitly) calls the toString method to output the undirected graph.
Compile and run:
Work $Javac Graph. javaNote: Graph. java uses unchecked or insecure operations. Note: For details, use-Xlint: unchecked to recompile. Work $Java Graph tinyG.txt13 vertices, 13 edges0: 6 2 1 5 1: 0 2: 0 3: 5 4 4: 5 6 3 5: 3 4 0 6: 0 4 7: 8 8: 7 9: 11 10 12 10: 9 11: 9 12 12: 11 9
The content of the tinyG.txt file here is as follows (the content is the same as that in the introduction, which is listed here for your convenience of copying and pasting. In the introduction, Images cannot be copied or pasted ):
work$ cat tinyG.txt13130 54 30 19 126 45 40 211 129 100 67 89 115 3
C # Program
Translate Graph. java in the previous section into a C # program to obtain Graph. cs:
1 using System; 2 using System.Text; 3 using System.Collections.Generic; 4 5 namespace Skyiv 6 { 7 public class Graph 8 { 9 public int V { get; private set; } // number of vertices10 public int E { get; private set; } // number of edges11 Stack<int>[] adj; // adjacency lists12 13 public Graph(int V)14 { Initialize(V); }15 16 public Graph(In @in)17 {18 Initialize(@in.ReadInt()); // Read V and construct this graph.19 int E = @in.ReadInt(); // Read E.20 for (var i = 0; i < E; i++)21 { // Add an edge.22 var v = @in.ReadInt(); // Read a vertex,23 var w = @in.ReadInt(); // read another vertex,24 AddEdge(v, w); // and add edge connecting them.25 }26 }27 28 void Initialize(int V)29 {30 this.V = V;31 adj = new Stack<int>[V]; // Create array of lists.32 for (int v = 0; v < V; v++) // Initialize all lists33 adj[v] = new Stack<int>(); // to empty.34 }35 36 public void AddEdge(int v, int w)37 {38 adj[v].Push(w); // Add w to v's list.39 adj[w].Push(v); // Add v to w's list.40 E++;41 }42 43 public IEnumerable<int> Adj(int v)44 { return adj[v]; }45 46 public override string ToString()47 {48 var s = new StringBuilder();49 s.AppendLine(V + " vertices, " + E + " edges");50 for (var v = 0; v < V; v++)51 {52 s.Append(v + ": ");53 foreach (var w in Adj(v)) s.Append(w + " ");54 s.AppendLine();55 }56 return s.ToString();57 }58 59 static void Main(string[] args)60 {61 var G = new Graph(new In(args[0]));62 Console.Write(G);63 }64 }65 }
The above C # program is basically a Java Program Translation:
- Lines 9th to 10 use the C # Attribute to replace the Java field, indicating the number of vertices V and number of edges E.
- Row 3 uses the generic Stack <int> type instead of the Java Bag <Integer> type to represent the adjacent tables of each vertex.
- C # language does not have the disadvantage of the Java language mentioned above. You can directly use the int type as a generic parameter.
- The two constructors from lines 13th to 26 are basically translated using the Java language version.
- The Initialize method from lines 28th to 34 is the first constructor translation in the Java language version.
- The 31st line creates an array of the adjacent tables. It does not have the disadvantage of the Java language. You can directly create a Generic Array without forcing transformation.
- Lines 46th to 57 of the ToString method are translated using the toString method of the Java language version. The StringBuilder class of C # language has the AppendLine method, so NEWLINE in the Java language version is not required.
- Other methods are basically the corresponding translations of the Java language version.
The compilation and running results are as follows:
work$ dmcs Graph.cs In.cswork$ mono Graph.exe tinyG.txt13 vertices, 13 edges0: 6 2 1 5 1: 0 2: 0 3: 5 4 4: 5 6 3 5: 3 4 0 6: 0 4 7: 8 8: 7 9: 11 10 12 10: 9 11: 9 12 12: 11 9
The running result is exactly the same as that of the Java program.
Comparison between Java and C # programs
Are the first two Graph. java and Graph. cs very similar? It can also be more like the Bag data type written by the author of algorithm (version 4th) in Graph. java, which can be replaced with the Stack data type in the Java standard library. In Graph. java:
- Replace all the bags with stacks.
- Replace the add values of rows 32nd and 33rd with push.
The modified Java program running result remains unchanged. In fact, the C # language, which was born in 2000, was greatly affected by the Java language that was born in 1995. It also took advantage of its latencies to inherit the advantages of the Java language and discard the disadvantages of Java. For example, the two disadvantages of the Java language mentioned earlier in terms of generics (this book also regrets these two shortcomings ), it does not exist in C. The Java language takes care of the previously written code and is forward compatible with each other. The history is too heavy. Scala is a new language on the Java platform and has a promising future. However, I personally prefer the C # language, mainly using the C # language to write programs.
C # program for feeding
In the Output for list-of-edges input diagram in the introduction, each edge is marked as red when it appears for the second time, which is manually marked by the author of algorithm (version 4th, instead of the actual running result of the program. If our program needs to do this, you can make the following changes in Graph. cs:
1. Add a statement (repeated is used as a field of the Graph class to mark the second edge) after row 3 ):
HashSet<Tuple<int, int>> repeated = new HashSet<Tuple<int, int>>();
2. Add a statement after row 3 (in the AddEdge method, mark the side that appears for the second time as red ):
repeated.Add(Tuple.Create(w, v));
3. Add the following Display method after row 3 (Display the secondary side in red ):
public void Display(){ var defaultColor = Console.ForegroundColor; Console.WriteLine("{0} vertices, {1} edges", V, E); for (var v = 0; v < V; v++) { Console.Write(v + ": "); foreach (var w in Adj(v)) { var red = repeated.Contains(Tuple.Create(v, w)); if (red) Console.ForegroundColor = ConsoleColor.Red; Console.Write(w + " "); if (red) Console.ForegroundColor = defaultColor; } Console.WriteLine(); }}
4. Change the statement of row 62nd to (in the Main method, use the Display method instead of the implicit ToString method ):
G.Display();
The following is the execution result of the modified program:
Read the input C # Helper Program
The source program of In. cs used earlier is as follows:
1 using System; 2 using System.IO; 3 4 namespace Skyiv 5 { 6 public class In : IDisposable 7 { 8 static readonly byte[] BLANKS = { 9, 10, 13, 32 }; // tab,lf,cr,space 9 static readonly byte EOF = 0; // assume '\0' not in input file10 11 byte[] buffer = new byte[64 * 1024];12 int current = 0, count = 0;13 Stream reader;14 15 public In() : this(Console.OpenStandardInput()) {}16 public In(string name) : this(File.OpenRead(name)) {}17 public In(Stream stream) { reader = stream; }18 19 byte ReadByte()20 {21 if (current >= count)22 {23 count = reader.Read(buffer, current = 0, buffer.Length);24 if (count == 0) return EOF;25 }26 return buffer[current++];27 }28 29 public int ReadInt()30 {31 var n = 0;32 var ok = false;33 for (byte b; (b = ReadByte()) != EOF; )34 {35 if (Array.IndexOf(BLANKS, b) >= 0)36 if (ok) break;37 else continue;38 n = n * 10 + (b - '0');39 ok = true;40 }41 return n;42 }43 44 public void Dispose()45 {46 if (reader != null) reader.Close();47 }48 }49 }
This procedure comes from references [7].
Running Environment
Our program runs in the 64-bit Arch Linux operating system. The Java environment is OpenJDK 1.7.0, And the. NET environment is Mono 3.0.6:
Work $Uname-Linux m6100t 3.7.10-1-ARCH #1 smp preempt Thu Feb 28 09:50:17 CET 2013 x86_64 GNU/Linuxwork $Java-versionJava version "1.7.0 _ 15" OpenJDK Runtime Environment (IcedTea7 2.3.7) (ArchLinux build 7. u13_2.3.7-2-x86_64) OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode) work $Javac-versionJavac 1.7.0 _ 15 work $Echo $ CLASSPATH/Home/ben/src/algs/stdlib. jar:/home/ben/src/algs/algs4.jarwork $Mono -- versionMono JIT compiler version 3.0.6 (tarball March 11, 2013 11:54:36 CST) Copyright (C) 2002-2012 Novell, Inc, Xamarin Inc and Contributors. www. mono-project.comTLS: _ threadSIGSEGV: altstackconfigurications: epollArchitecture: amd64Disabled: noneMisc: softdebug LLVM: supported, not enabled. GC: encoded ded Boehm (with typed GC and Parallel Mark) work $Dmcs -- versionMono C # compiler version 3.0.6.0
Note: To compile and run the Java program in this article, you need to set the CLASSPATH environment variable. For details, refer to [3].
Copyright statement: This article is the original author of the http://www.zuiniusn.com, not allowed by the blogger can not be reproduced.