aboutsummaryrefslogtreecommitdiff
path: root/src/com.example.portfolio3/com/example/portfolio3/GraphAlgorithms.java
blob: 9337ac16254714762310279b90f63dddf302fd41 (plain)
  1. package com.example.portfolio3;
  2. // origin: <https://moodle.ruc.dk/course/section.php?id=211877>
  3. import java.io.BufferedReader;
  4. import java.io.BufferedReader;
  5. import java.io.FileReader;
  6. import java.io.FileWriter;
  7. import java.io.IOException;
  8. import java.io.PrintWriter;
  9. import java.util.ArrayList;
  10. import java.util.Collection;
  11. import java.util.Collections;
  12. import java.util.HashMap;
  13. import java.util.HashSet;
  14. import java.util.List;
  15. import java.util.Set;
  16. /// foo
  17. public class GraphAlgorithms {
  18. /// foo
  19. GraphAlgorithms() {}
  20. /// Calculates the length of a path or any other collection of edes
  21. ///
  22. /// does not require the edges to form a path
  23. /// @param edges foo
  24. /// @return int
  25. public static int pathLength(Collection<Edge> edges){
  26. return edges.stream().mapToInt(e-> e.weight()).sum();
  27. }
  28. /// checks whether a list of edges form a path so that
  29. ///
  30. /// the to-vertex in one edge is the from-vertex of the next
  31. /// @param edges foo
  32. /// @return boolean
  33. public static boolean isPath(List<Edge> edges){
  34. for(int i=1;i<edges.size();i++){
  35. if(edges.get(i-1).to()!=edges.get(i).from())return false;
  36. }
  37. return true;
  38. }
  39. ///Calculates the length of a path vertices in a graph
  40. ///
  41. /// return null if vertices are not connected as a path
  42. /// @param g foo
  43. /// @param path foo
  44. /// @return Integer
  45. public static Integer pathLength(Graph g,List<Vertex> path){
  46. int length=0;
  47. for(int i=1;i<path.size();i++){
  48. Integer w=g.getWeight(path.get(i-1),path.get(i));
  49. if(w==null)return null;
  50. length+=w;
  51. }
  52. return length;
  53. }
  54. //------------------------------------------------------------
  55. //
  56. // Comparators and sorting methods
  57. /// Comparator of edges based on weight
  58. ///
  59. /// can be used for sorting a list of edges
  60. /// @param e1 foo
  61. /// @param e2 foo
  62. /// @return int
  63. static int cmpEdgeWeight(Edge e1,Edge e2) {
  64. int w1=e1.weight(),w2=e2.weight();
  65. if(w1!=w2)return w1-w2;
  66. if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
  67. return e1.to().name().compareTo(e2.to().name());
  68. }
  69. /// Comparator of edges based on from-vertex
  70. ///
  71. /// can be used for sorting a list of edges
  72. /// @param e1 foo
  73. /// @param e2 foo
  74. /// @return int
  75. static int cmpEdgeFrom(Edge e1,Edge e2) {
  76. if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
  77. int w1=e1.weight(),w2=e2.weight();
  78. if(w1!=w2)return w1-w2;
  79. return e1.to().name().compareTo(e2.to().name());
  80. }
  81. /// Comparator of edges based on from-vertex
  82. ///
  83. /// can be used for sorting a list of edges
  84. /// @param e1 foo
  85. /// @param e2 foo
  86. /// @return int
  87. static int cmpEdgeTo(Edge e1,Edge e2) {
  88. if(e1.to()!=e2.to())return e1.to().name().compareTo(e2.to().name());
  89. if(e1.from()!=e2.from())return e1.from().name().compareTo(e2.from().name());
  90. int w1=e1.weight(),w2=e2.weight();
  91. return w1-w2;
  92. }
  93. /// sort a collection of edges based on their weights
  94. /// @param edges foo
  95. /// @return List<Edge>
  96. static List<Edge> sortEdges(Collection<Edge> edges){
  97. ArrayList<Edge> list=new ArrayList<>(edges);
  98. Collections.sort(list,GraphAlgorithms::cmpEdgeWeight);
  99. return list;
  100. }
  101. /// sort a collection of edges based on from-vertex
  102. /// @param edges foo
  103. /// @return List<Edge>
  104. static List<Edge> sortEdgesFrom(Collection<Edge> edges){
  105. ArrayList<Edge> list=new ArrayList<>(edges);
  106. Collections.sort(list,GraphAlgorithms::cmpEdgeFrom);
  107. return list;
  108. }
  109. /// sort a collection of edges based on to-vertex
  110. /// @param edges foo
  111. /// @return List<Edge>
  112. static List<Edge> sortEdgesTo(Collection<Edge> edges){
  113. ArrayList<Edge> list=new ArrayList<>(edges);
  114. Collections.sort(list,GraphAlgorithms::cmpEdgeTo);
  115. return list;
  116. }
  117. /// sort a collection of vertices based on their name
  118. /// @param vertices foo
  119. /// @return List<Vertex>
  120. public static List<Vertex> sortVertex(Collection<Vertex> vertices){
  121. ArrayList<Vertex> list=new ArrayList<>(vertices);
  122. Collections.sort(list,(Vertex v1,Vertex v2)-> v1.name().compareTo(v2.name()));
  123. return list;
  124. }
  125. //------------------------------------------------------------
  126. //
  127. // Algorithms for traverse and minimum spanning tree
  128. /// traverse a graph depth first from a given vertex
  129. /// return the set of visited vertices
  130. /// @param g foo
  131. /// @param v foo
  132. /// @return Set<Vertex>
  133. public static Set<Vertex> visitBreadthFirst(Graph g,Vertex v){
  134. HashSet<Vertex> thisLevel=new HashSet<>();
  135. HashSet<Vertex> nextLevel=new HashSet<>();
  136. HashSet<Vertex> visited=new HashSet<>();
  137. thisLevel.add(v);
  138. while(thisLevel.size()>0){
  139. System.out.println("level "+thisLevel);
  140. for(Vertex w:thisLevel){
  141. //System.out.println("visited "+w);
  142. visited.add(w);
  143. Collection<Edge> outedge=g.outEdge(w);
  144. if(outedge==null)continue;
  145. for(Edge e: outedge){
  146. if(visited.contains(e.to()))continue;
  147. if(thisLevel.contains(e.to()))continue;
  148. nextLevel.add(e.to());
  149. }
  150. }
  151. thisLevel=nextLevel;
  152. nextLevel=new HashSet<Vertex>();
  153. }
  154. return visited;
  155. }
  156. /// traverse a graph depth first from a given vertex
  157. /// return the set of visited vertices
  158. /// @param g foo
  159. /// @param v foo
  160. /// @return Set<Vertex>
  161. public static Set<Vertex> visitDepthFirst(Graph g,Vertex v){
  162. HashSet<Vertex> visit=new HashSet<>();
  163. visitDepthFirst(g, v,visit);
  164. return visit;
  165. }
  166. /// foo
  167. /// @param g foo
  168. /// @param v foo
  169. /// @param visited foo
  170. private static void visitDepthFirst(Graph g,Vertex v,Set<Vertex> visited){
  171. if(visited.contains(v))return;
  172. //System.out.println("visited "+v);
  173. visited.add(v);
  174. for(Edge e: g.outEdge(v))
  175. visitDepthFirst(g,e.to(),visited);
  176. }
  177. /// an implementation of Prim's algorithm
  178. /// naive implementation without priorityqueue
  179. /// @param g foo
  180. /// @return Set<Edge>
  181. public static Set<Edge> minimumSpanningTree(Graph g){
  182. Collection<Edge> edges=g.edges();
  183. HashSet<Edge> mst=new HashSet<>();
  184. HashSet<Vertex> frontier=new HashSet<>();
  185. for(Edge e:edges){frontier.add(e.from());break;}
  186. while(true) {
  187. Edge nearest = null;
  188. for (Edge e : edges) {
  189. if (!frontier.contains(e.from())) continue;
  190. if (frontier.contains(e.to())) continue;
  191. if (nearest == null || nearest.weight() > e.weight())
  192. nearest = e;
  193. }
  194. if(nearest==null)break;
  195. mst.add(nearest);
  196. frontier.add(nearest.to());
  197. }
  198. return mst;
  199. }
  200. /// returns the tree of shortest paths from start to
  201. /// all vertices in the graph
  202. ///
  203. /// naive implementation without a prorityqueue
  204. /// @param g foo
  205. /// @param start foo
  206. /// @return Set<Edge>
  207. public static Set<Edge> dijkstra(Graph g, Vertex start){
  208. // create table for done, prev and weight from start
  209. int maxint =Integer.MAX_VALUE;
  210. HashSet<Vertex> done=new HashSet<>();
  211. HashMap<Vertex,Edge> prev=new HashMap<>();
  212. HashMap<Vertex,Integer> weight=new HashMap<>();
  213. for(Vertex w:g.vertices())weight.put(w,maxint);
  214. // start node is done, distance 0 from start
  215. weight.put(start,0);
  216. done.add(start);
  217. while(true){
  218. // find nearest from a done vertex
  219. Vertex nearest = null;
  220. int neardist = maxint;
  221. Edge done2near=null;
  222. for(Vertex w1:done){
  223. for (Edge e : g.outEdge(w1)) {
  224. Vertex w2 = e.to();
  225. if (done.contains(w2)) continue;
  226. if ((weight.get(w1) + e.weight()) < neardist) {
  227. nearest = e.to();
  228. neardist = weight.get(w1) + e.weight();
  229. done2near = e;
  230. }
  231. }
  232. }
  233. // System.out.println("find nearest "+done2near);
  234. // if no more, then we are done
  235. if (nearest == null) break;
  236. // update distance from this node to other nodes
  237. for (Edge e1 : g.outEdge(nearest)) {
  238. Vertex w3 = e1.to();
  239. int wght = e1.weight();
  240. if (weight.get(w3) > (neardist + wght)) {
  241. weight.put(w3, neardist + wght);
  242. }
  243. }
  244. done.add(nearest);
  245. prev.put(nearest,done2near);
  246. weight.put(nearest,neardist);
  247. }
  248. return new HashSet<Edge>(prev.values());
  249. }
  250. //------------------------------------------------------------
  251. //
  252. // IO operations
  253. /// read a comma-separated file in the format
  254. /// <vertex> , <vertex> , <weight>
  255. ///
  256. /// stores file as bidirectional graph
  257. /// @param g foo
  258. /// @param file foo
  259. public static void readGraph(Graph g, String file) {
  260. try{
  261. BufferedReader in = new BufferedReader(new FileReader(file));
  262. for(String line=in.readLine(); line!=null; line=in.readLine()) {
  263. if(line.length()==0) continue;
  264. String[] arr = line.split(",");
  265. if(arr.length!=3) throw new RuntimeException("CSV file format error: "+line);
  266. g.insertEdge(arr[0].trim(), arr[1].trim(), Integer.parseInt(arr[2].trim()));
  267. g.insertEdge(arr[1].trim(), arr[0].trim(), Integer.parseInt(arr[2].trim()));
  268. }
  269. in.close();
  270. }catch(IOException e){
  271. throw new RuntimeException(e);
  272. }
  273. }
  274. /// foo
  275. /// @param g foo
  276. public static void printGraph(Graph g) {
  277. for(Vertex v: sortVertex(g.vertices())) {
  278. System.out.println(v.toString());
  279. for(Edge e:sortEdgesTo(g.outEdge(v)))
  280. System.out.println(" "+e.toString());
  281. }
  282. }
  283. /// store a list of lines as a file
  284. /// @param list foo
  285. /// @param f foo
  286. public static void storeStrings(List<String> list,String f){
  287. try{
  288. PrintWriter out=new PrintWriter(new FileWriter(f));
  289. for(String s:list){
  290. out.println(s);
  291. }
  292. out.close();
  293. }catch(IOException e){
  294. throw new RuntimeException(e);
  295. }
  296. }
  297. /// read a file a returns a list of lines
  298. /// @param f foo
  299. /// @return ArrayList
  300. public static ArrayList<String> loadStrings(String f){
  301. ArrayList<String> list=new ArrayList<>();
  302. try{
  303. BufferedReader in=new BufferedReader(new FileReader(f));
  304. while(true){
  305. String s=in.readLine();
  306. if(s==null)break;
  307. list.add(s);
  308. }
  309. in.close();
  310. }catch(IOException e){
  311. throw new RuntimeException(e);
  312. }
  313. return list;
  314. }
  315. }