Adds Trie

master
Abhinav Sarkar 2019-07-07 16:35:26 +05:30
parent b179302265
commit 714d013fdb
2 changed files with 230 additions and 0 deletions

View File

@ -10,6 +10,10 @@ public interface Map<K, V> extends Iterable<Map.Entry<K, V>>
void remove(K key);
default boolean contains(K key) {
return this.get(key).isPresent();
}
class Entry<K2, V2> {
private final K2 key;
private final V2 val;

View File

@ -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;
}
}