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