Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #547 from pablopareja/pablo_master

Lowest common ancestor pull request
  • Loading branch information...
commit 8919b28dfe523e843935a4bf70381498fd25875b 2 parents a7ac953 + 8f7e5a2
@tinwelint authored
View
118 graph-algo/src/main/java/org/neo4j/graphalgo/impl/ancestor/AncestorsUtil.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2002-2012 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.neo4j.graphalgo.impl.ancestor;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.graphdb.RelationshipExpander;
+
+/**
+ * @author Pablo Pareja Tobes
+ */
+public class AncestorsUtil {
+
+ /**
+ *
+ * @param nodeSet Set of nodes for which the LCA will be found.
+ * @param relationshipType Relationship type used to look for the LCA
+ * @param relationshipDirection Direction of the relationships used (seen from the descendant node)
+ * @return The LCA node if there's one, null otherwise.
+ */
+ public static Node lowestCommonAncestor(List<Node> nodeSet,
+ RelationshipExpander expander) {
+
+ Node lowerCommonAncestor = null;
+
+ if (nodeSet.size() > 1) {
+
+ Node firstNode = nodeSet.get(0);
+ LinkedList<Node> firstAncestors = getAncestorsPlusSelf(firstNode, expander);
+
+ for (int i = 1; i < nodeSet.size() && !firstAncestors.isEmpty(); i++) {
+ Node currentNode = nodeSet.get(i);
+ lookForCommonAncestor(firstAncestors, currentNode, expander);
+ }
+
+ if(!firstAncestors.isEmpty()){
+ lowerCommonAncestor = firstAncestors.get(0);
+ }
+
+ }
+
+ return lowerCommonAncestor;
+ }
+
+ private static LinkedList<Node> getAncestorsPlusSelf(Node node,
+ RelationshipExpander expander) {
+
+ LinkedList<Node> ancestors = new LinkedList<Node>();
+
+ ancestors.add(node);
+ Iterator<Relationship> relIterator = expander.expand(node).iterator();
+
+ while (relIterator.hasNext()) {
+
+ Relationship rel = relIterator.next();
+ node = rel.getOtherNode(node);
+
+ ancestors.add(node);
+
+ relIterator = expander.expand(node).iterator();
+
+ }
+
+ return ancestors;
+
+ }
+
+ private static void lookForCommonAncestor(LinkedList<Node> commonAncestors,
+ Node currentNode,
+ RelationshipExpander expander) {
+
+ while (currentNode != null) {
+
+ for (int i = 0; i < commonAncestors.size(); i++) {
+ Node node = commonAncestors.get(i);
+ if (node.getId() == currentNode.getId()) {
+ for (int j = 0; j < i; j++) {
+ commonAncestors.pollFirst();
+ }
+ return;
+ }
+ }
+
+ Iterator<Relationship> relIt = expander.expand(currentNode).iterator();
+
+ if (relIt.hasNext()) {
+
+ Relationship rel = relIt.next();
+
+ currentNode = rel.getOtherNode(currentNode);
+
+ }else{
+ currentNode = null;
+ }
+ }
+
+ }
+}
View
147 graph-algo/src/test/java/org/neo4j/graphalgo/impl/ancestor/AncestorTestCase.java
@@ -0,0 +1,147 @@
+/**
+ * Copyright (c) 2002-2012 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.neo4j.graphalgo.impl.ancestor;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.neo4j.graphdb.Direction;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.RelationshipExpander;
+import org.neo4j.graphdb.RelationshipType;
+import org.neo4j.kernel.Traversal;
+import org.neo4j.test.GraphDescription;
+import org.neo4j.test.GraphDescription.Graph;
+import org.neo4j.test.GraphHolder;
+import org.neo4j.test.ImpermanentGraphDatabase;
+import org.neo4j.test.TestData;
+
+public class AncestorTestCase implements GraphHolder
+{
+
+ public @Rule
+ TestData<Map<String, Node>> data = TestData.producedThrough( GraphDescription.createGraphFor(
+ this, true ) );
+ private static GraphDatabaseService gdb;
+
+ @Test
+ @Graph( { "root contains child1", "child1 contains child11",
+ "child1 contains child12", "root contains child2",
+ "child12 contains child121", "child1 contains child13" } )
+ public void test()
+ {
+ RelationshipExpander expander = Traversal.expanderForTypes(Rels.contains, Direction.INCOMING);
+
+ List<Node> nodeSet = new ArrayList<Node>();
+ Map<String, Node> graph = data.get();
+ nodeSet.add( graph.get( "child1" ) );
+ nodeSet.add( graph.get( "root" ) );
+
+ Node ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "root" ), ancestor);
+
+ nodeSet.clear();
+ nodeSet.add( graph.get( "child12" ) );
+ nodeSet.add( graph.get( "child11" ) );
+ ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "child1" ), ancestor);
+
+ nodeSet.clear();
+ nodeSet.add( graph.get( "child121" ) );
+ nodeSet.add( graph.get( "child12" ) );
+ ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "child12" ), ancestor);
+
+ nodeSet.clear();
+ nodeSet.add( graph.get( "child11" ) );
+ nodeSet.add( graph.get( "child13" ) );
+ ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "child1" ), ancestor);
+
+ nodeSet.clear();
+ nodeSet.add( graph.get( "child2" ) );
+ nodeSet.add( graph.get( "child121" ) );
+ ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "root" ), ancestor);
+
+ nodeSet.clear();
+ nodeSet.add( graph.get( "child11" ) );
+ nodeSet.add( graph.get( "child12" ) );
+ nodeSet.add( graph.get( "child13" ) );
+ ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "child1" ), ancestor);
+
+ nodeSet.clear();
+ nodeSet.add( graph.get( "child11" ) );
+ nodeSet.add( graph.get( "child12" ) );
+ nodeSet.add( graph.get( "child13" ) );
+ nodeSet.add( graph.get( "child121" ) );
+ ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "child1" ), ancestor);
+
+ nodeSet.clear();
+ nodeSet.add( graph.get( "child11" ) );
+ nodeSet.add( graph.get( "child12" ) );
+ nodeSet.add( graph.get( "child13" ) );
+ nodeSet.add( graph.get( "child121" ) );
+ nodeSet.add( graph.get( "child2" ) );
+ ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "root" ), ancestor);
+
+ nodeSet.clear();
+ nodeSet.add( graph.get( "child11" ) );
+ nodeSet.add( graph.get( "child12" ) );
+ nodeSet.add( graph.get( "child13" ) );
+ nodeSet.add( graph.get( "child121" ) );
+ nodeSet.add( graph.get( "child12" ) );
+ nodeSet.add( graph.get( "root" ) );
+ ancestor = AncestorsUtil.lowestCommonAncestor( nodeSet, expander);
+ assertEquals(graph.get( "root" ), ancestor);
+ }
+
+ @Override
+ public GraphDatabaseService graphdb()
+ {
+ return gdb;
+ }
+
+ @BeforeClass
+ public static void before()
+ {
+ gdb = new ImpermanentGraphDatabase();
+ }
+ @AfterClass
+ public static void after()
+ {
+ gdb.shutdown();
+ }
+ enum Rels implements RelationshipType
+ {
+ contains;
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.