▶ 书中第四章部分程序,包括在加上自己补充的代码,图的几种补充数据结构,包括无向 / 有向符号图,有权边结构,有边权有向图
● 无向符号图
1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdIn; 5 import edu.princeton.cs.algs4.StdOut; 6 import edu.princeton.cs.algs4.Graph; 7 import edu.princeton.cs.algs4.ST; 8 9 public class class01 10 { 11 private ST<String, Integer> st; // 字符串转索引 12 private String[] keys; // 索引转字符串 13 private Graph graph; 14 15 public class01(String filename, String delimiter) 16 { 17 st = new ST<String, Integer>(); 18 for (In in = new In(filename); !in.isEmpty();) // 收集符号,存入集合,编号 19 { 20 String[] a = in.readLine().split(delimiter); 21 for (int i = 0; i < a.length; i++) 22 { 23 if (!st.contains(a[i])) 24 st.put(a[i], st.size()); 25 } 26 } 27 keys = new String[st.size()]; 28 for (String name : st.keys()) 29 keys[st.get(name)] = name; 30 graph = new Graph(st.size()); 31 for (In in = new In(filename); in.hasNextLine();) // 再读一次,建图 32 { 33 String[] a = in.readLine().split(delimiter); 34 int v = st.get(a[0]); 35 for (int i = 1; i < a.length; i++) 36 { 37 int w = st.get(a[i]); 38 graph.addEdge(v, w); 39 } 40 } 41 } 42 43 public boolean contains(String s) 44 { 45 return st.contains(s); 46 } 47 48 public int indexOf(String s) 49 { 50 return st.get(s); 51 } 52 53 public String nameOf(int v) 54 { 55 return keys[v]; 56 } 57 58 public Graph graph() 59 { 60 return graph; 61 } 62 63 public static void main(String[] args) 64 { 65 String filename = args[0]; // 输入符号图(邻接表)的文件名和分隔符 66 String delimiter = args[1]; 67 class01 sg = new class01(filename, delimiter); 68 for (Graph graph = sg.graph(); StdIn.hasNextLine();) 69 { 70 String source = StdIn.readLine(); // 再输入需要查询的顶点 71 if (sg.contains(source)) 72 { 73 int s = sg.indexOf(source); 74 for (int v : graph.adj(s)) 75 StdOut.println(" " + sg.nameOf(v)); 76 } 77 else 78 StdOut.println("input not contain '" + source + "'"); 79 } 80 } 81 }
● 有向符号图,与无向情形仅有方法名不同
1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdIn; 5 import edu.princeton.cs.algs4.StdOut; 6 import edu.princeton.cs.algs4.Digraph; 7 import edu.princeton.cs.algs4.ST; 8 9 public class class01 10 { 11 private ST<String, Integer> st; 12 private String[] keys; 13 private Digraph graph; 14 15 public class01(String filename, String delimiter) 16 { 17 st = new ST<String, Integer>(); 18 for (In in = new In(filename); !in.isEmpty();) 19 { 20 String[] a = in.readLine().split(delimiter); 21 for (int i = 0; i < a.length; i++) 22 { 23 if (!st.contains(a[i])) 24 st.put(a[i], st.size()); 25 } 26 } 27 keys = new String[st.size()]; 28 for (String name : st.keys()) 29 keys[st.get(name)] = name; 30 graph = new Graph(st.size()); 31 for (In in = new In(filename); in.hasNextLine();) // 再读一次,建图 32 { 33 String[] a = in.readLine().split(delimiter); 34 int v = st.get(a[0]); 35 for (int i = 1; i < a.length; i++) 36 { 37 int w = st.get(a[i]); 38 graph.addEdge(v, w); 39 } 40 } 41 } 42 43 public boolean contains(String s) 44 { 45 return st.contains(s); 46 } 47 48 public int indexOf(String s) 49 { 50 return st.get(s); 51 } 52 53 public String nameOf(int v) 54 { 55 return keys[v]; 56 } 57 58 public Digraph digraph() 59 { 60 return graph; 61 } 62 63 public static void main(String[] args) 64 { 65 String filename = args[0]; 66 String delimiter = args[1]; 67 class01 sg = new class01(filename, delimiter); 68 for (Digraph graph = sg.digraph(); StdIn.hasNextLine();) 69 { 70 String t = StdIn.readLine(); 71 for (int v : graph.adj(sg.indexOf(t))) 72 StdOut.println(" " + sg.nameOf(v)); 73 } 74 } 75 }
● 有权边结构
1 package package01; 2 3 import edu.princeton.cs.algs4.StdOut; 4 import edu.princeton.cs.algs4.Edge; 5 6 public class class01 implements Comparable<Edge> 7 { 8 private final int v; 9 private final int w; 10 private final double weight; 11 12 public class01(int inputV, int inputW, double inputWeight) 13 { 14 if (inputV < 0 || inputW < 0 || Double.isNaN(inputWeight)) 15 throw new IllegalArgumentException(" <Construtor> v < 0 || w < 0 || weight == NaN. "); 16 v = inputV; 17 w = inputW; 18 weight = inputWeight; 19 } 20 21 public double weight() 22 { 23 return weight; 24 } 25 26 public int either() 27 { 28 return v; 29 } 30 31 public int other(int vertex) 32 { 33 if (vertex == v) 34 return w; 35 if (vertex == w) 36 return v; 37 throw new IllegalArgumentException(" <other> No such point. "); 38 } 39 40 @Override 41 public int compareTo(class01 that) 42 { 43 return Double.compare(weight, that.weight); 44 } 45 46 public String toString() 47 { 48 return String.format("%d-%d %.5f", v, w, weight); 49 } 50 51 public static void main(String[] args) 52 { 53 class01 e = new class01(12, 34, 5.67); 54 StdOut.println(e); 55 } 56 }
● 有边权有向图
1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.StdRandom; 6 import edu.princeton.cs.algs4.Bag; 7 import edu.princeton.cs.algs4.Stack; 8 import edu.princeton.cs.algs4.Edge; 9 10 public class class01 11 { 12 private static final String NEWLINE = System.getProperty("line.separator");// 换行,按操作系统适配 13 14 private final int V; 15 private int E; 16 private Bag<Edge>[] adj; 17 18 public class01(int inputV) 19 { 20 if (inputV < 0) 21 throw new IllegalArgumentException(" <Constructor> V < 0. "); 22 V = inputV; 23 E = 0; 24 adj = (Bag<Edge>[]) new Bag[V]; 25 for (int v = 0; v < V; v++) 26 adj[v] = new Bag<Edge>(); 27 } 28 29 public class01(int inputV, int inputE) 30 { 31 this(inputV); 32 if (inputE < 0) 33 throw new IllegalArgumentException(" <Constructor> E < 0. "); 34 for (int i = 0; i < E; i++) // 添加 E 条边,随机权重 35 { 36 int v = StdRandom.uniform(V); 37 int w = StdRandom.uniform(V); 38 Edge e = new Edge(v, w, Math.round(100 * StdRandom.uniform()) / 100.0); 39 addEdge(e); 40 } 41 } 42 43 public class01(In in) 44 { 45 this(in.readInt()); 46 E = in.readInt(); 47 if (E < 0) 48 throw new IllegalArgumentException(" <Constructor> E < 0. "); 49 for (int i = 0; i < E; i++) 50 { 51 int v = in.readInt(); 52 int w = in.readInt(); 53 Edge e = new Edge(v, w, in.readDouble()); 54 addEdge(e); 55 } 56 } 57 58 public class01(class01 G) 59 { 60 this(G.V()); 61 E = G.E(); 62 for (int v = 0; v < G.V(); v++) 63 { 64 Stack<Edge> reverse = new Stack<Edge>();// 用栈保存原图遍历得到的边,吐栈是回复顺序 65 for (Edge e : G.adj[v]) 66 reverse.push(e); 67 for (Edge e : reverse) 68 adj[v].add(e); 69 } 70 } 71 72 public int V() 73 { 74 return V; 75 } 76 77 public int E() 78 { 79 return E; 80 } 81 82 public void addEdge(Edge e) 83 { 84 int v = e.either(); 85 int w = e.other(v); 86 adj[v].add(e); 87 adj[w].add(e); 88 E++; 89 } 90 91 public Iterable<Edge> adj(int v) 92 { 93 return adj[v]; 94 } 95 96 public int degree(int v) 97 { 98 return adj[v].size(); 99 } 100 101 public Iterable<Edge> edges() 102 { 103 Bag<Edge> list = new Bag<Edge>(); 104 for (int v = 0; v < V; v++) 105 { 106 boolean selfLoop = false; // 注意两条自边只算一个自环 107 for (Edge e : adj(v)) 108 { 109 if (e.other(v) == v) 110 { 111 if (!selfLoop) 112 list.add(e); 113 selfLoop = !selfLoop; 114 } 115 if (e.other(v) > v) // 索引控制,防止反复添加同一条边 116 list.add(e); 117 } 118 } 119 return list; 120 } 121 122 public String toString() 123 { 124 StringBuilder s = new StringBuilder(); 125 s.append(V + " " + E + NEWLINE); 126 for (int v = 0; v < V; v++) 127 { 128 s.append(v + ": "); 129 for (Edge e : adj[v]) 130 s.append(e + " "); 131 s.append(NEWLINE); 132 } 133 return s.toString(); 134 } 135 136 public static void main(String[] args) 137 { 138 In in = new In(args[0]); 139 class01 G = new class01(in); 140 StdOut.println(G); 141 } 142 }