Author: simonetripodi
Date: Wed Jul 6 01:18:25 2011
New Revision: 1143237
URL: http://svn.apache.org/viewvc?rev=1143237&view=rev
Log:
added Kruskal's algorithm implementation, optimized by a simple DisjointSet (find-union) implementation
as described on wikipedia [http://en.wikipedia.org/wiki/Disjoint-set_data_structure]
Added:
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSet.java
(with props)
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSetNode.java
(with props)
commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/KruskalTestCase.java
(with props)
Modified:
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Kruskal.java
Added: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSet.java
URL: http://svn.apache.org/viewvc/commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSet.java?rev=1143237&view=auto
==============================================================================
--- commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSet.java
(added)
+++ commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSet.java
Wed Jul 6 01:18:25 2011
@@ -0,0 +1,117 @@
+package org.apache.commons.graph.spanning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.graph.Vertex;
+
+/**
+ * Simple <a href="http://en.wikipedia.org/wiki/Disjoint-set_data_structure">Disjoint-set</a>
implementation.
+ *
+ * @param <V> the Graph vertices type.
+ */
+final class DisjointSet<V extends Vertex>
+{
+
+ private final Map<V, DisjointSetNode<V>> disjointSets = new HashMap<V,
DisjointSetNode<V>>();
+
+ /**
+ * Performs the find applying the <i>path compression</i>.
+ *
+ * @param vertex
+ * @return
+ */
+ public V find( V vertex )
+ {
+ DisjointSetNode<V> vertexNode = find( getNode( vertex ) );
+
+ if ( vertexNode == vertexNode.getParent() )
+ {
+ return vertexNode.getVertex();
+ }
+
+ vertexNode.setParent( find( vertexNode.getParent() ) );
+
+ return vertexNode.getParent().getVertex();
+ }
+
+ /**
+ * Performs the find applying the <i>path compression</i>.
+ *
+ * @param node
+ * @return
+ */
+ private DisjointSetNode<V> find( DisjointSetNode<V> node )
+ {
+ if ( node == node.getParent() )
+ {
+ return node;
+ }
+ return find( node.getParent() );
+ }
+
+ /**
+ * Performs the merge by applying the <i>union by rank</i>.
+ *
+ * @param u
+ * @param v
+ */
+ public void union( V u, V v )
+ {
+ DisjointSetNode<V> uRoot = find( getNode( u ) );
+ DisjointSetNode<V> vRoot = find( getNode( v ) );
+
+ if ( uRoot == vRoot )
+ {
+ return;
+ }
+
+ int comparison = uRoot.compareTo( vRoot );
+ if ( comparison < 0 )
+ {
+ uRoot.setParent( vRoot );
+ }
+ else if ( comparison > 0 )
+ {
+ vRoot.setParent( uRoot );
+ }
+ else
+ {
+ vRoot.setParent( uRoot );
+ uRoot.increaseRank();
+ }
+ }
+
+ private DisjointSetNode<V> getNode( V vertex )
+ {
+ DisjointSetNode<V> node = disjointSets.get( vertex );
+
+ if ( node == null )
+ {
+ node = new DisjointSetNode<V>( vertex );
+ disjointSets.put( vertex, node );
+ }
+
+ return node;
+ }
+
+}
Propchange: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSet.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSet.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSet.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSetNode.java
URL: http://svn.apache.org/viewvc/commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSetNode.java?rev=1143237&view=auto
==============================================================================
--- commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSetNode.java
(added)
+++ commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSetNode.java
Wed Jul 6 01:18:25 2011
@@ -0,0 +1,87 @@
+package org.apache.commons.graph.spanning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.commons.graph.Vertex;
+
+/**
+ * The {@link DisjointSet} internal node representation.
+ *
+ * @param <V> the Graph vertices type.
+ */
+final class DisjointSetNode<V extends Vertex>
+ implements Comparable<DisjointSetNode<V>>
+{
+
+ private final V vertex;
+
+ private DisjointSetNode<V> parent = this;
+
+ private Integer rank = 0;
+
+ /**
+ *
+ *
+ * @param vertex
+ */
+ public DisjointSetNode( V vertex )
+ {
+ this.vertex = vertex;
+ }
+
+ public V getVertex()
+ {
+ return vertex;
+ }
+
+ public DisjointSetNode<V> getParent()
+ {
+ return parent;
+ }
+
+ public void setParent( DisjointSetNode<V> parent )
+ {
+ this.parent = parent;
+ }
+
+ public Integer getRank()
+ {
+ return rank;
+ }
+
+ public void increaseRank()
+ {
+ rank++;
+ }
+
+ public void setRank( int rank )
+ {
+ this.rank = rank;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo( DisjointSetNode<V> o )
+ {
+ return rank.compareTo( o.getRank() );
+ }
+
+}
Propchange: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSetNode.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSetNode.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/DisjointSetNode.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Kruskal.java
URL: http://svn.apache.org/viewvc/commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Kruskal.java?rev=1143237&r1=1143236&r2=1143237&view=diff
==============================================================================
--- commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Kruskal.java
(original)
+++ commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Kruskal.java
Wed Jul 6 01:18:25 2011
@@ -19,10 +19,16 @@ package org.apache.commons.graph.spannin
* under the License.
*/
-import org.apache.commons.graph.Graph;
+import java.util.HashSet;
+import java.util.PriorityQueue;
+import java.util.Set;
+
+import org.apache.commons.graph.SpanningTree;
import org.apache.commons.graph.Vertex;
+import org.apache.commons.graph.VertexPair;
import org.apache.commons.graph.WeightedEdge;
import org.apache.commons.graph.WeightedGraph;
+import org.apache.commons.graph.model.MutableSpanningTree;
/**
* Kruskal's algorithm is an algorithm in graph theory that finds a minimum spanning tree
@@ -39,9 +45,46 @@ public final class Kruskal
* @param graph the Graph for which minimum spanning tree (or forest) has to be calculated.
* @return the minimum spanning tree (or forest) of the input Graph.
*/
- public static <V extends Vertex, WE extends WeightedEdge> Graph<V, WE> minimumSpanningTree(
WeightedGraph<V, WE> graph )
+ public static <V extends Vertex, WE extends WeightedEdge> SpanningTree<V, WE>
minimumSpanningTree( WeightedGraph<V, WE> graph )
{
- return null;
+ final Set<V> settledNodes = new HashSet<V>();
+
+ final PriorityQueue<WE> orderedEdges = new PriorityQueue<WE>( graph.getSize()
);
+
+ for ( WE edge : graph.getEdges() )
+ {
+ orderedEdges.add( edge );
+ }
+
+ final DisjointSet<V> disjointSet = new DisjointSet<V>();
+
+ MutableSpanningTree<V, WE> spanningTree = new MutableSpanningTree<V, WE>();
+
+ while ( settledNodes.size() < graph.getOrder() )
+ {
+ WE edge = orderedEdges.poll();
+
+ VertexPair<V> vertices = graph.getVertices( edge );
+ V head = vertices.getHead();
+ V tail = vertices.getTail();
+
+ if ( settledNodes.add( head ) )
+ {
+ spanningTree.addVertex( head );
+ }
+ if ( settledNodes.add( tail ) )
+ {
+ spanningTree.addVertex( tail );
+ }
+
+ if ( !disjointSet.find( head ).equals( disjointSet.find( tail ) ) )
+ {
+ disjointSet.union( head, tail );
+ spanningTree.addEdge( head, edge, tail );
+ }
+ }
+
+ return spanningTree;
}
}
Added: commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/KruskalTestCase.java
URL: http://svn.apache.org/viewvc/commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/KruskalTestCase.java?rev=1143237&view=auto
==============================================================================
--- commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/KruskalTestCase.java
(added)
+++ commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/KruskalTestCase.java
Wed Jul 6 01:18:25 2011
@@ -0,0 +1,104 @@
+package org.apache.commons.graph.spanning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static junit.framework.Assert.assertEquals;
+import static org.apache.commons.graph.spanning.Kruskal.minimumSpanningTree;
+
+import org.apache.commons.graph.SpanningTree;
+import org.apache.commons.graph.model.BaseLabeledVertex;
+import org.apache.commons.graph.model.BaseLabeledWeightedEdge;
+import org.apache.commons.graph.model.MutableSpanningTree;
+import org.apache.commons.graph.model.UndirectedMutableWeightedGraph;
+import org.junit.Test;
+
+public final class KruskalTestCase
+{
+
+ /**
+ * Test Graph and Prim's solution can be seen on
+ * <a href="http://en.wikipedia.org/wiki/Prim%27s_algorithm">Wikipedia</a>
+ */
+ @Test
+ public void verifyWikipediaMinimumSpanningTree()
+ {
+ UndirectedMutableWeightedGraph<BaseLabeledVertex, BaseLabeledWeightedEdge>
input
+ = new UndirectedMutableWeightedGraph<BaseLabeledVertex, BaseLabeledWeightedEdge>();
+
+ BaseLabeledVertex a = new BaseLabeledVertex( "A" );
+ BaseLabeledVertex b = new BaseLabeledVertex( "B" );
+ BaseLabeledVertex c = new BaseLabeledVertex( "C" );
+ BaseLabeledVertex d = new BaseLabeledVertex( "D" );
+ BaseLabeledVertex e = new BaseLabeledVertex( "E" );
+ BaseLabeledVertex f = new BaseLabeledVertex( "F" );
+ BaseLabeledVertex g = new BaseLabeledVertex( "G" );
+
+ input.addVertex( a );
+ input.addVertex( b );
+ input.addVertex( c );
+ input.addVertex( d );
+ input.addVertex( e );
+ input.addVertex( f );
+ input.addVertex( g );
+
+ input.addEdge( a, new BaseLabeledWeightedEdge( "a <-> b", 7D ), b );
+ input.addEdge( a, new BaseLabeledWeightedEdge( "a <-> d", 5D ), d );
+
+ input.addEdge( b, new BaseLabeledWeightedEdge( "b <-> c", 8D ), c );
+ input.addEdge( b, new BaseLabeledWeightedEdge( "b <-> d", 9D ), d );
+ input.addEdge( b, new BaseLabeledWeightedEdge( "b <-> e", 7D ), e );
+
+ input.addEdge( c, new BaseLabeledWeightedEdge( "c <-> e", 5D ), e );
+
+ input.addEdge( d, new BaseLabeledWeightedEdge( "d <-> e", 15D ), e );
+ input.addEdge( d, new BaseLabeledWeightedEdge( "d <-> f", 6D ), f );
+
+ input.addEdge( e, new BaseLabeledWeightedEdge( "e <-> f", 8D ), f );
+ input.addEdge( e, new BaseLabeledWeightedEdge( "e <-> g", 9D ), g );
+
+ input.addEdge( f, new BaseLabeledWeightedEdge( "f <-> g", 11D ), g );
+
+ // expected
+
+ MutableSpanningTree<BaseLabeledVertex, BaseLabeledWeightedEdge> expected =
+ new MutableSpanningTree<BaseLabeledVertex, BaseLabeledWeightedEdge>();
+
+ for ( BaseLabeledVertex vertex : input.getVertices() )
+ {
+ expected.addVertex( vertex );
+ }
+
+ expected.addEdge( a, new BaseLabeledWeightedEdge( "a <-> b", 7D ), b );
+ expected.addEdge( a, new BaseLabeledWeightedEdge( "a <-> d", 5D ), d );
+ expected.addEdge( b, new BaseLabeledWeightedEdge( "b <-> e", 9D ), e );
+ expected.addEdge( c, new BaseLabeledWeightedEdge( "c <-> e", 5D ), e );
+ expected.addEdge( d, new BaseLabeledWeightedEdge( "d <-> f", 6D ), f );
+ expected.addEdge( e, new BaseLabeledWeightedEdge( "e <-> g", 9D ), g );
+
+ // Actual
+
+ SpanningTree<BaseLabeledVertex, BaseLabeledWeightedEdge> actual = minimumSpanningTree(
input );
+
+ // assert!
+
+ assertEquals( expected, actual );
+ }
+
+}
Propchange: commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/KruskalTestCase.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/KruskalTestCase.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/KruskalTestCase.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
|