Adds Trie
parent
b179302265
commit
714d013fdb
|
@ -10,6 +10,10 @@ public interface Map<K, V> extends Iterable<Map.Entry<K, V>>
|
||||||
|
|
||||||
void remove(K key);
|
void remove(K key);
|
||||||
|
|
||||||
|
default boolean contains(K key) {
|
||||||
|
return this.get(key).isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
class Entry<K2, V2> {
|
class Entry<K2, V2> {
|
||||||
private final K2 key;
|
private final K2 key;
|
||||||
private final V2 val;
|
private final V2 val;
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
package net.abhinavsarkar.algorist;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class Trie<K extends Comparable<K>, V> implements SortedMap<K, V>
|
||||||
|
{
|
||||||
|
private final Function<K, ? extends int[]> keyToStringFn;
|
||||||
|
private Node<V> root;
|
||||||
|
|
||||||
|
public Trie(Function<K, int[]> keyToStringFn, int minBound, int maxBound) {
|
||||||
|
|
||||||
|
this.keyToStringFn = keyToStringFn;
|
||||||
|
root = new RootNode<>(maxBound - minBound + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<K> minimum()
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<K> maximum()
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<K> successor(K key)
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<K> predecessor(K key)
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(K key, V val)
|
||||||
|
{
|
||||||
|
root.put(keyToStringFn.apply(key), 0, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<V> get(K key)
|
||||||
|
{
|
||||||
|
return this.root.get(keyToStringFn.apply(key), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(K key)
|
||||||
|
{
|
||||||
|
this.root.remove(keyToStringFn.apply(key), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry<K, V>> iterator()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface Node<V> {
|
||||||
|
void put(int[] chars, int idx, V val);
|
||||||
|
Optional<V> get(int[] chars, int idx);
|
||||||
|
boolean remove(int[] chars, int idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RootNode<V> implements Node<V> {
|
||||||
|
protected final ValueNode<V>[] children;
|
||||||
|
protected final int capacity;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private RootNode(int capacity)
|
||||||
|
{
|
||||||
|
children = new ValueNode[capacity];
|
||||||
|
this.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(int[] chars, int idx, V val)
|
||||||
|
{
|
||||||
|
if (idx != 0) {
|
||||||
|
throw new IllegalArgumentException("index must be zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chars.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children[chars[idx]] == null)
|
||||||
|
{
|
||||||
|
children[chars[idx]] = new ValueNode<>(null, capacity);
|
||||||
|
}
|
||||||
|
children[chars[idx]].put(chars, idx+1, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<V> get(int[] chars, int idx)
|
||||||
|
{
|
||||||
|
if (idx != 0) {
|
||||||
|
throw new IllegalArgumentException("index must be zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children[chars[idx]] == null)
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return children[chars[idx]].get(chars, idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(int[] chars, int idx)
|
||||||
|
{
|
||||||
|
if (idx != 0) {
|
||||||
|
throw new IllegalArgumentException("index must be zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
doRemove(chars, idx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doRemove(int[] chars, int idx)
|
||||||
|
{
|
||||||
|
if (children[chars[idx]] != null && children[chars[idx]].remove(chars, idx + 1))
|
||||||
|
{
|
||||||
|
children[chars[idx]] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ValueNode<V> extends RootNode<V> {
|
||||||
|
private V val;
|
||||||
|
|
||||||
|
private ValueNode(V val, int capacity)
|
||||||
|
{
|
||||||
|
super(capacity);
|
||||||
|
this.val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(int[] chars, int idx, V val) {
|
||||||
|
if (idx > chars.length) {
|
||||||
|
throw new IllegalArgumentException("index too big");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chars.length == idx) {
|
||||||
|
this.val = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children[chars[idx]] == null)
|
||||||
|
{
|
||||||
|
children[chars[idx]] = new ValueNode<>(null, capacity);
|
||||||
|
}
|
||||||
|
children[chars[idx]].put(chars, idx+1, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<V> get(int[] chars, int idx)
|
||||||
|
{
|
||||||
|
if (chars.length == idx) {
|
||||||
|
return Optional.ofNullable(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children[chars[idx]] == null)
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return children[chars[idx]].get(chars, idx+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(int[] chars, int idx)
|
||||||
|
{
|
||||||
|
if (chars.length == idx) {
|
||||||
|
val = null;
|
||||||
|
} else {
|
||||||
|
doRemove(chars, idx);
|
||||||
|
}
|
||||||
|
return Arrays.stream(children).noneMatch(Objects::nonNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException
|
||||||
|
{
|
||||||
|
Trie<String, String> trie = new Trie<>(s -> stringToIntArray(s, 'A'), 'A', 'z');
|
||||||
|
try (Stream<String> lines = Files.lines(Paths.get("/usr/share/dict/words")))
|
||||||
|
{
|
||||||
|
lines.forEach(line -> trie.put(line, line));
|
||||||
|
}
|
||||||
|
System.out.println(trie.contains("abactor"));
|
||||||
|
System.out.println(trie.contains("a"));
|
||||||
|
System.out.println(trie.contains("bbb"));
|
||||||
|
System.out.println(trie.contains("aardwolf"));
|
||||||
|
trie.remove("aardwolf");
|
||||||
|
System.out.println(trie.contains("aardwolf"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] stringToIntArray(String s, char min)
|
||||||
|
{
|
||||||
|
int[] ints = new int[s.length()];
|
||||||
|
char[] charArray = s.toCharArray();
|
||||||
|
for (int i = 0; i < charArray.length; i++)
|
||||||
|
{
|
||||||
|
char c = charArray[i];
|
||||||
|
if (c >= min)
|
||||||
|
{
|
||||||
|
ints[i] = c - min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ints;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue