/** * Returns minimum spanning tree. Method uses Kruskal's algorithm for this purpose. Working only * for undirected graph * * @return map represents branches of minimum-spanning-tree (key - child, value - parent) */ public static Map<Integer, Integer> minTreeKruskal(Graph graph) { if (graph.isDirected()) throw new UnsupportedOperationException( "Kruscal's algorithm works only for undirected graphs"); Map<Integer, Integer> tree = new HashMap<>(); // get all edges via iterator List<Graph.Edge> edges = new ArrayList<>(); for (Graph.Edge edge : graph.edges()) edges.add(edge); // sort edges by weight Collections.sort( edges, new Comparator<Graph.Edge>() { @Override public int compare(Graph.Edge o1, Graph.Edge o2) { return o1.getWeight() - o2.getWeight(); } }); // for algorithm we use disjoint set forest data structure (a.k.a. union-find, merge-find etc. // see wikipedia) DisjointSetForest<Integer> set = new DisjointSetForest<>(); for (Integer number : graph.vertexes()) set.makeSet(number); // adding edges to tree, while it can't be possible to add edge that don't creates a cycle for (Graph.Edge edge : edges) { if (set.find(edge.getIn()) != set.find(edge.getOut())) { if (!tree.containsKey(edge.getIn())) tree.put(edge.getIn(), edge.getOut()); else tree.put(edge.getOut(), edge.getIn()); set.union(edge.getIn(), edge.getOut()); } } return tree; }
/** * Returns maximum spanning tree. Method uses Prim's algorithm for this purpose. Working only for * undirected graph * * @return map represents branches of maximum-spanning-tree (key - child, value - parent) */ public static Map<Integer, Integer> maxTreePrim(Graph graph) { if (graph.isDirected()) throw new UnsupportedOperationException("Prim's algorithm works only for undirected graphs"); Map<Integer, Integer> tree = new HashMap<>(); List<Graph.Edge> edges = new ArrayList<>(); Set<Integer> labeled = new HashSet<>(); Iterator<Integer> vertexIt = graph.vertexes().iterator(); // continue while there are vertexes to add while (vertexIt.hasNext()) { int vertex = vertexIt.next(); // if vertex is labeled - skip it if (labeled.contains(vertex)) continue; labeled.add(vertex); // Add to list all edges adjacent to vertex edges.addAll(graph.getAdjacentEdges(vertex)); // While we have edges to add while (!edges.isEmpty()) { // sort all edges by weight Collections.sort( edges, new Comparator<Graph.Edge>() { @Override public int compare(Graph.Edge o1, Graph.Edge o2) { return o2.getWeight() - o1.getWeight(); } }); Iterator<Graph.Edge> it = edges.iterator(); while (it.hasNext()) { Graph.Edge edge = it.next(); if (!labeled.contains(edge.getIn())) { labeled.add(edge.getIn()); edges.addAll(graph.getAdjacentEdges(edge.getIn())); tree.put(edge.getIn(), edge.getOut()); break; } if (!labeled.contains(edge.getOut())) { labeled.add(edge.getOut()); edges.addAll(graph.getAdjacentEdges(edge.getOut())); tree.put(edge.getOut(), edge.getIn()); break; } it.remove(); } } } return tree; }
@After public void validateGraphState() { new EqualsTester() .addEqualityGroup(network, Graphs.copyOf(network), ImmutableNetwork.copyOf(network)) .testEquals(); String networkString = network.toString(); assertThat(networkString).contains("isDirected: " + network.isDirected()); assertThat(networkString).contains("allowsParallelEdges: " + network.allowsParallelEdges()); assertThat(networkString).contains("allowsSelfLoops: " + network.allowsSelfLoops()); int nodeStart = networkString.indexOf("nodes:"); int edgeStart = networkString.indexOf("edges:"); String nodeString = networkString.substring(nodeStart, edgeStart); String edgeString = networkString.substring(edgeStart); Graph<Integer> asGraph = network.asGraph(); assertThat(network.nodes()).isEqualTo(asGraph.nodes()); assertThat(network.nodeOrder()).isEqualTo(asGraph.nodeOrder()); assertThat(network.isDirected()).isEqualTo(asGraph.isDirected()); assertThat(network.allowsSelfLoops()).isEqualTo(asGraph.allowsSelfLoops()); for (String edge : network.edges()) { // TODO(b/27817069): Consider verifying the edge's incident nodes in the string. assertThat(edgeString).contains(edge); Iterator<Integer> endpointsIterator = network.incidentNodes(edge).iterator(); Integer nodeA = endpointsIterator.next(); Integer nodeB = endpointsIterator.next(); assertThat(network.edgesConnecting(nodeA, nodeB)).contains(edge); assertThat(network.successors(nodeA)).contains(nodeB); assertThat(network.adjacentNodes(nodeA)).contains(nodeB); assertThat(network.outEdges(nodeA)).contains(edge); assertThat(network.incidentEdges(nodeA)).contains(edge); assertThat(network.predecessors(nodeB)).contains(nodeA); assertThat(network.adjacentNodes(nodeB)).contains(nodeA); assertThat(network.inEdges(nodeB)).contains(edge); assertThat(network.incidentEdges(nodeB)).contains(edge); for (Integer incidentNode : network.incidentNodes(edge)) { assertThat(network.nodes()).contains(incidentNode); for (String adjacentEdge : network.incidentEdges(incidentNode)) { assertTrue( edge.equals(adjacentEdge) || network.adjacentEdges(edge).contains(adjacentEdge)); } } } for (Integer node : network.nodes()) { assertThat(nodeString).contains(node.toString()); assertThat(network.adjacentNodes(node)).isEqualTo(asGraph.adjacentNodes(node)); assertThat(network.predecessors(node)).isEqualTo(asGraph.predecessors(node)); assertThat(network.successors(node)).isEqualTo(asGraph.successors(node)); for (Integer otherNode : network.nodes()) { Set<String> edgesConnecting = network.edgesConnecting(node, otherNode); boolean isSelfLoop = node.equals(otherNode); if (network.isDirected() || !isSelfLoop) { assertThat(edgesConnecting) .isEqualTo(Sets.intersection(network.outEdges(node), network.inEdges(otherNode))); } if (!network.allowsParallelEdges()) { assertThat(edgesConnecting.size()).isAtMost(1); } if (!network.allowsSelfLoops() && isSelfLoop) { assertThat(edgesConnecting).isEmpty(); } for (String edge : edgesConnecting) { assertThat(network.incidentNodes(edge)).isEqualTo(Endpoints.of(network, node, otherNode)); } } for (String incidentEdge : network.incidentEdges(node)) { assertTrue( network.inEdges(node).contains(incidentEdge) || network.outEdges(node).contains(incidentEdge)); assertThat(network.edges()).contains(incidentEdge); assertThat(network.incidentNodes(incidentEdge)).contains(node); } for (String inEdge : network.inEdges(node)) { assertThat(network.incidentEdges(node)).contains(inEdge); assertThat(network.outEdges(network.incidentNodes(inEdge).adjacentNode(node))) .contains(inEdge); } for (String outEdge : network.outEdges(node)) { assertThat(network.incidentEdges(node)).contains(outEdge); assertThat(network.inEdges(network.incidentNodes(outEdge).adjacentNode(node))) .contains(outEdge); } for (Integer adjacentNode : network.adjacentNodes(node)) { assertTrue( network.predecessors(node).contains(adjacentNode) || network.successors(node).contains(adjacentNode)); assertTrue( !network.edgesConnecting(node, adjacentNode).isEmpty() || !network.edgesConnecting(adjacentNode, node).isEmpty()); } for (Integer predecessor : network.predecessors(node)) { assertThat(network.successors(predecessor)).contains(node); assertThat(network.edgesConnecting(predecessor, node)).isNotEmpty(); } for (Integer successor : network.successors(node)) { assertThat(network.predecessors(successor)).contains(node); assertThat(network.edgesConnecting(node, successor)).isNotEmpty(); } } }
@Override public boolean init(Graph graph) { return !(graph.getNodeCount() == 0 || !(graph.isDirected())); }
@Override public final boolean isDirected() { return g.isDirected(); }