-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #382 from gdgib/G2-1652-TrieAPI
G2-1652 Basic Trie API & Implementation
- Loading branch information
Showing
12 changed files
with
364 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
ax-adt/src/main/java/com/g2forge/alexandria/adt/trie/ITrie.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.g2forge.alexandria.adt.trie; | ||
|
||
import com.g2forge.alexandria.java.fluent.optional.IOptional; | ||
import com.g2forge.alexandria.path.path.IPath; | ||
|
||
public interface ITrie<KT, V> { | ||
public IOptional<V> get(IPath<KT> path); | ||
} |
32 changes: 30 additions & 2 deletions
32
ax-adt/src/main/java/com/g2forge/alexandria/adt/trie/Node.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,33 @@ | ||
package com.g2forge.alexandria.adt.trie; | ||
|
||
import com.g2forge.alexandria.adt.graph.v2.member.ASingleGraphMember; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class Node extends ASingleGraphMember {} | ||
import com.g2forge.alexandria.path.path.IPath; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.ToString; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
@ToString | ||
@EqualsAndHashCode | ||
public class Node<KT, V> { | ||
protected final IPath<KT> label; | ||
|
||
protected final Map<KT, Node<KT, V>> children; | ||
|
||
protected boolean isTerminal; | ||
|
||
protected V value; | ||
|
||
public Node(IPath<KT> label) { | ||
this(label, new HashMap<>(), false, null); | ||
} | ||
|
||
public Node(IPath<KT> label, V value) { | ||
this(label, new HashMap<>(), true, value); | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
ax-adt/src/main/java/com/g2forge/alexandria/adt/trie/Trie.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.g2forge.alexandria.adt.trie; | ||
|
||
import com.g2forge.alexandria.java.fluent.optional.IOptional; | ||
import com.g2forge.alexandria.java.fluent.optional.NullableOptional; | ||
import com.g2forge.alexandria.path.path.IPath; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@AllArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter(AccessLevel.PROTECTED) | ||
public class Trie<KT, V> implements ITrie<KT, V> { | ||
protected Node<KT, V> root; | ||
|
||
@Override | ||
public IOptional<V> get(IPath<KT> path) { | ||
final Node<KT, V> root = getRoot(); | ||
Node<KT, V> current; | ||
|
||
// Create an artificial parent of the root, if the root is labeled | ||
if ((root.getLabel() != null) && !root.getLabel().isEmpty()) { | ||
current = new Node<>(null); | ||
current.getChildren().put(getRoot().getLabel().getFirst(), getRoot()); | ||
} else current = root; | ||
|
||
int index = 0; | ||
while (index < path.size()) { | ||
// Find the child | ||
final Node<KT, V> next = current.getChildren().get(path.getComponent(index)); | ||
if (next == null) return NullableOptional.empty(); | ||
|
||
// Ensure the label on the next node isn't longer than the path | ||
final int nextLabelSize = next.getLabel().size(); | ||
if (path.size() < (index + nextLabelSize)) return NullableOptional.empty(); | ||
|
||
// Ensure the label on the next node matches the path | ||
final IPath<KT> subPath = path.subPath(index, index + nextLabelSize); | ||
if (!subPath.equals(next.getLabel())) return NullableOptional.empty(); | ||
|
||
current = next; | ||
index += nextLabelSize; | ||
} | ||
|
||
return current.isTerminal() ? NullableOptional.of(current.getValue()) : NullableOptional.empty(); | ||
} | ||
|
||
} |
41 changes: 41 additions & 0 deletions
41
ax-adt/src/test/java/com/g2forge/alexandria/adt/trie/NodeBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.g2forge.alexandria.adt.trie; | ||
|
||
import com.g2forge.alexandria.java.core.helpers.HArray; | ||
import com.g2forge.alexandria.java.function.IConsumer1; | ||
import com.g2forge.alexandria.java.function.builder.IBuilder; | ||
import com.g2forge.alexandria.path.path.IPath; | ||
import com.g2forge.alexandria.path.path.Path; | ||
|
||
public class NodeBuilder implements IBuilder<Node<Character, String>> { | ||
public interface IChildBuilder { | ||
public NodeBuilder child(String label, String value); | ||
} | ||
|
||
public static IPath<Character> toLabel(String label) { | ||
return new Path<>(HArray.toObject(label.toCharArray())); | ||
} | ||
|
||
protected final Node<Character, String> node; | ||
|
||
public NodeBuilder(String label, String value) { | ||
if (value == null) this.node = new Node<>(toLabel(label)); | ||
else this.node = new Node<>(toLabel(label), value); | ||
} | ||
|
||
@Override | ||
public Node<Character, String> build() { | ||
return node; | ||
} | ||
|
||
public NodeBuilder children(IConsumer1<NodeBuilder.IChildBuilder> consumer) { | ||
consumer.accept(new IChildBuilder() { | ||
@Override | ||
public NodeBuilder child(String label, String value) { | ||
final NodeBuilder retVal = new NodeBuilder(label, value); | ||
node.getChildren().put(retVal.node.getLabel().getFirst(), retVal.node); | ||
return retVal; | ||
} | ||
}); | ||
return this; | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
ax-adt/src/test/java/com/g2forge/alexandria/adt/trie/TestNodeBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.g2forge.alexandria.adt.trie; | ||
|
||
import org.junit.Test; | ||
|
||
import com.g2forge.alexandria.path.path.Path; | ||
import com.g2forge.alexandria.test.HAssert; | ||
|
||
public class TestNodeBuilder { | ||
@Test | ||
public void root() { | ||
HAssert.assertEquals(new Node<>(new Path<Character>()), new NodeBuilder("", null).build());;; | ||
} | ||
|
||
@Test | ||
public void label() { | ||
HAssert.assertEquals(new Node<>(new Path<Character>('a', 'b', 'c')), new NodeBuilder("abc", null).build());;; | ||
} | ||
|
||
@Test | ||
public void child() { | ||
final Node<Character, String> expected = new Node<>(new Path<Character>('a', 'b', 'c')); | ||
expected.getChildren().put('d', new Node<>(new Path<Character>('d'), "value")); | ||
HAssert.assertEquals(expected, new NodeBuilder("abc", null).children(c -> c.child("d", "value")).build());;; | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
ax-adt/src/test/java/com/g2forge/alexandria/adt/trie/TestTrie3Node.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.g2forge.alexandria.adt.trie; | ||
|
||
import org.junit.Test; | ||
|
||
import com.g2forge.alexandria.java.fluent.optional.IOptional; | ||
import com.g2forge.alexandria.test.HAssert; | ||
|
||
public class TestTrie3Node { | ||
protected static final ITrie<Character, String> trie = new Trie<>(new NodeBuilder("t", null).children(c -> { | ||
c.child("est", "test"); | ||
c.child("oast", "toast"); | ||
}).build()); | ||
|
||
@Test | ||
public void roast() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("roast")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
|
||
@Test | ||
public void temp() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("temp")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
|
||
@Test | ||
public void test() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("test")); | ||
HAssert.assertTrue(result.isNotEmpty()); | ||
HAssert.assertEquals("test", result.get()); | ||
} | ||
|
||
@Test | ||
public void toast() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("toast")); | ||
HAssert.assertTrue(result.isNotEmpty()); | ||
HAssert.assertEquals("toast", result.get()); | ||
} | ||
|
||
@Test | ||
public void toaster() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("toaster")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
|
||
@Test | ||
public void toasting() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("toasting")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
|
||
@Test | ||
public void toasti() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("toasti")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
|
||
@Test | ||
public void trip() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("trip")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
ax-adt/src/test/java/com/g2forge/alexandria/adt/trie/TestTrie5Node.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package com.g2forge.alexandria.adt.trie; | ||
|
||
import org.junit.Test; | ||
|
||
import com.g2forge.alexandria.java.fluent.optional.IOptional; | ||
import com.g2forge.alexandria.test.HAssert; | ||
|
||
public class TestTrie5Node { | ||
protected static final ITrie<Character, String> trie = new Trie<>(new NodeBuilder("t", null).children(c0 -> { | ||
c0.child("est", "test"); | ||
c0.child("oast", "toast").children(c1 -> { | ||
c1.child("er", "toaster"); | ||
c1.child("ing", "toasting"); | ||
}); | ||
}).build()); | ||
|
||
@Test | ||
public void roast() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("roast")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
|
||
@Test | ||
public void temp() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("temp")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
|
||
@Test | ||
public void test() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("test")); | ||
HAssert.assertTrue(result.isNotEmpty()); | ||
HAssert.assertEquals("test", result.get()); | ||
} | ||
|
||
@Test | ||
public void toast() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("toast")); | ||
HAssert.assertTrue(result.isNotEmpty()); | ||
HAssert.assertEquals("toast", result.get()); | ||
} | ||
|
||
@Test | ||
public void toaster() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("toaster")); | ||
HAssert.assertTrue(result.isNotEmpty()); | ||
HAssert.assertEquals("toaster", result.get()); | ||
} | ||
|
||
@Test | ||
public void toasti() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("toasti")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
|
||
@Test | ||
public void toasting() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("toasting")); | ||
HAssert.assertTrue(result.isNotEmpty()); | ||
HAssert.assertEquals("toasting", result.get()); | ||
} | ||
|
||
@Test | ||
public void trip() { | ||
final IOptional<String> result = trie.get(NodeBuilder.toLabel("trip")); | ||
HAssert.assertFalse(result.isNotEmpty()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.