public class PatriciaTrie<K,V> extends AbstractMap<K,V> implements Trie<K,V>, Serializable
PATRICIA = Practical Algorithm to Retrieve Information Coded in Alphanumeric
A PATRICIA Trie is a compressed Trie. Instead of storing all data at the edges of the Trie (and having empty internal nodes), PATRICIA stores data in every node. This allows for very efficient traversal, insert, delete, predecessor, successor, prefix, range, and 'select' operations. All operations are performed at worst in O(K) time, where K is the number of bits in the largest item in the tree. In practice, operations actually take O(A(K)) time, where A(K) is the average number of bits of all items in the tree.
Most importantly, PATRICIA requires very few comparisons to keys while doing any operation. While performing a lookup, each comparison (at most K of them, described above) will perform a single bit comparison against the given key, instead of comparing the entire key to another key.
The Trie can return operations in lexicographical order using the 'traverse',
'prefix', 'submap', or 'iterator' methods. The Trie can also scan for items
that are 'bitwise' (using an XOR metric) by the 'select' method. Bitwise
closeness is determined by the PatriciaTrie.KeyAnalyzer
returning true or
false for a bit being set or not in a given key.
This PATRICIA Trie supports both variable length & fixed length keys.
Some methods, such as getPrefixedBy(...)
are suited only to
variable length keys, whereas getPrefixedByBits(...)
is suited
to fixed-size keys.
Additionally see PATRICIA for more information.
Any methods here that take an Object
may throw a
ClassCastException
if the method is expecting an instance of K
(and it isn't K).
PatriciaTrie<String, String> trie = new PatriciaTrie<String, String> (new CharSequenceKeyAnalyzer()); trie.put("Lime", "Lime"); trie.put("LimeWire", "LimeWire"); trie.put("LimeRadio", "LimeRadio"); trie.put("Lax", "Lax"); trie.put("Lake", "Lake"); trie.put("Lovely", "Lovely"); System.out.println(trie.select("Lo")); System.out.println(trie.select("Lime")); System.out.println(trie.getPrefixedBy("La").toString()); Output: Lovely Lime {Lake=Lake, Lax=Lax}
Modifier and Type | Class and Description |
---|---|
private static class |
PatriciaTrie.EmptyIterator |
private class |
PatriciaTrie.EntryIterator |
private class |
PatriciaTrie.EntrySet |
static interface |
PatriciaTrie.KeyAnalyzer<K>
Defines the interface to analyze
Trie keys on a bit
level. |
private class |
PatriciaTrie.KeyIterator |
private class |
PatriciaTrie.KeySet |
private class |
PatriciaTrie.NodeIterator<E>
An iterator for the entries.
|
private class |
PatriciaTrie.PrefixEntryIterator
An iterator for iterating over a prefix search.
|
private class |
PatriciaTrie.PrefixSubMap
A submap used for prefix views over the Trie.
|
private class |
PatriciaTrie.SingletonIterator
An iterator that stores a single TrieEntry.
|
private class |
PatriciaTrie.SubMap |
private class |
PatriciaTrie.SubMapEntryIterator
An iterator for submaps.
|
private static class |
PatriciaTrie.TrieEntry<K,V>
The actual Trie nodes.
|
private class |
PatriciaTrie.ValueIterator |
private class |
PatriciaTrie.Values |
AbstractMap.SimpleEntry<K,V>, AbstractMap.SimpleImmutableEntry<K,V>
Trie.Cursor<K,V>
Modifier and Type | Field and Description |
---|---|
private Set<Map.Entry<K,V>> |
entrySet |
private PatriciaTrie.KeyAnalyzer<? super K> |
keyAnalyzer
The keyAnalyzer used to analyze bit values of keys.
|
private Set<K> |
keySet
Each of these fields are initialized to contain an instance of the
appropriate view the first time this view is requested.
|
private int |
modCount
The number of times this has been modified (to fail-fast the iterators).
|
private PatriciaTrie.TrieEntry<K,V> |
root
The root element of the Trie.
|
private static long |
serialVersionUID |
private int |
size
The current size (total number of elements) of the Trie.
|
private Collection<V> |
values |
Constructor and Description |
---|
PatriciaTrie(PatriciaTrie.KeyAnalyzer<? super K> keyAnalyzer)
Constructs a new PatriciaTrie using the given keyAnalyzer.
|
Modifier and Type | Method and Description |
---|---|
private PatriciaTrie.TrieEntry<K,V> |
addEntry(PatriciaTrie.TrieEntry<K,V> toAdd,
int keyLength)
Adds the given entry into the Trie.
|
protected K |
asKey(Object key)
Gets the key as a 'K'.
|
private int |
bitIndex(K key,
K foundKey)
Utility method for calling
keyAnalyzer.bitIndex(key, 0, length(key), foundKey, 0, length(foundKey))
|
protected PatriciaTrie.TrieEntry<K,V> |
ceilingEntry(K key)
Returns a key-value mapping associated with the least key greater
than or equal to the given key, or null if there is no such key.
|
void |
clear()
Clears the Trie (i.e. removes all elements).
|
Comparator<? super K> |
comparator()
Returns the KeyAnalyzer as a comparator.
|
boolean |
containsKey(Object k)
Returns true if this trie contains the specified Key
This may throw ClassCastException if the object is not
of type K.
|
boolean |
containsValue(Object o)
Returns true if this Trie contains the specified value.
|
private void |
decrementSize()
Decrements the size and increments the mod counter.
|
Set<Map.Entry<K,V>> |
entrySet() |
private PatriciaTrie.TrieEntry<K,V> |
firstEntry()
Returns the first entry the Trie is storing.
|
K |
firstKey() |
protected PatriciaTrie.TrieEntry<K,V> |
floorEntry(K key)
Returns a key-value mapping associated with the greatest key
less than or equal to the given key, or null if there is no such key.
|
private PatriciaTrie.TrieEntry<K,V> |
followLeft(PatriciaTrie.TrieEntry<K,V> node)
Goes left through the tree until it finds a valid node.
|
protected PatriciaTrie.TrieEntry<K,V> |
followRight(PatriciaTrie.TrieEntry<K,V> node)
Traverses down the right path until it finds an uplink.
|
V |
get(Object k)
Returns the Value whose Key equals our lookup Key
or null if no such key exists.
|
(package private) PatriciaTrie.TrieEntry<K,V> |
getEntry(Object k)
Returns the entry associated with the specified key in the
PatriciaTrie.
|
PatriciaTrie.KeyAnalyzer<? super K> |
getKeyAnalyzer()
Returns the KeyAnalyzer that constructed the trie.
|
private PatriciaTrie.TrieEntry<K,V> |
getNearestEntryForKey(K key,
int keyLength)
Returns the nearest entry for a given key.
|
SortedMap<K,V> |
getPrefixedBy(K key)
Returns a view of this Trie of all elements that are
prefixed by the given key.
|
SortedMap<K,V> |
getPrefixedBy(K key,
int length)
Returns a view of this Trie of all elements that are
prefixed by the length of the key.
|
SortedMap<K,V> |
getPrefixedBy(K key,
int offset,
int length)
Returns a view of this Trie of all elements that are prefixed
by the key, starting at the given offset and for the given length.
|
SortedMap<K,V> |
getPrefixedByBits(K key,
int bitLength)
Returns a view of this Trie of all elements that are prefixed
by the number of bits in the given Key.
|
private SortedMap<K,V> |
getPrefixedByBits(K key,
int offset,
int length)
Returns a view of this map, with entries containing only those that
are prefixed by a value whose bits matches the bits between 'offset'
and 'length' in the given key.
|
SortedMap<K,V> |
headMap(K toKey) |
protected PatriciaTrie.TrieEntry<K,V> |
higherEntry(K key)
Returns an entry strictly higher than the given key,
or null if no such entry exists.
|
private void |
incrementModCount()
Increments the mod counter.
|
private void |
incrementSize()
Increments both the size and mod counter.
|
private boolean |
isBitSet(K key,
int keyLength,
int bitIndex)
Returns whether or not the given bit on the
key is set, or false if the key is null
|
boolean |
isEmpty()
Returns true if the Trie is empty
|
private static boolean |
isEqualBitKey(int bitIndex)
Returns true if bitIndex is a EQUAL_BIT_KEY
|
private static boolean |
isNullBitKey(int bitIndex)
Returns true if bitIndex is a NULL_BIT_KEY
|
private static boolean |
isValidBitIndex(int bitIndex)
Returns true if bitIndex is a valid index
|
private boolean |
isValidUplink(PatriciaTrie.TrieEntry<K,V> next,
PatriciaTrie.TrieEntry<K,V> from)
Returns true if 'next' is a valid uplink coming from 'from'.
|
Set<K> |
keySet()
Returns a set view of the keys contained in this map.
|
private PatriciaTrie.TrieEntry<K,V> |
lastEntry()
Returns the last entry the Trie is storing.
|
K |
lastKey() |
private int |
length(K key)
Returns the length of the key, or 0 if the key is null.
|
protected PatriciaTrie.TrieEntry<K,V> |
lowerEntry(K key)
Returns a key-value mapping associated with the greatest key
strictly less than the given key, or null if there is no such key.
|
(package private) Iterator<Map.Entry<K,V>> |
newEntryIterator() |
(package private) Iterator<K> |
newKeyIterator() |
(package private) Iterator<V> |
newValueIterator() |
private PatriciaTrie.TrieEntry<K,V> |
nextEntry(PatriciaTrie.TrieEntry<K,V> node)
Returns the entry lexicographically after the given entry.
|
private PatriciaTrie.TrieEntry<K,V> |
nextEntryImpl(PatriciaTrie.TrieEntry<K,V> start,
PatriciaTrie.TrieEntry<K,V> previous,
PatriciaTrie.TrieEntry<K,V> tree)
Scans for the next node, starting at the specified point, and using 'previous'
as a hint that the last node we returned was 'previous' (so we know not to return
it again).
|
private PatriciaTrie.TrieEntry<K,V> |
nextEntryInSubtree(PatriciaTrie.TrieEntry<K,V> node,
PatriciaTrie.TrieEntry<K,V> parentOfSubtree)
Returns the entry lexicographically after the given entry.
|
private PatriciaTrie.TrieEntry<K,V> |
previousEntry(PatriciaTrie.TrieEntry<K,V> start)
Returns the node lexicographically before the given node (or null if none).
|
V |
put(K key,
V value)
Adds a new
|
V |
remove(Object k)
Removes a Key from the Trie if one exists
This may throw ClassCastException if the object is not of type K.
|
private V |
removeEntry(PatriciaTrie.TrieEntry<K,V> h)
Removes a single entry from the Trie.
|
private void |
removeExternalEntry(PatriciaTrie.TrieEntry<K,V> h)
Removes an external entry from the Trie.
|
private void |
removeInternalEntry(PatriciaTrie.TrieEntry<K,V> h)
Removes an internal entry from the Trie.
|
V |
select(K key)
Returns the Value whose Key has the longest prefix
in common with our lookup key.
|
Map.Entry<K,V> |
select(K key,
Trie.Cursor<? super K,? super V> cursor)
Iterates through the Trie, starting with the entry whose bitwise
value is closest in an XOR metric to the given key.
|
private boolean |
selectR(PatriciaTrie.TrieEntry<K,V> h,
int bitIndex,
K key,
int keyLength,
PatriciaTrie.TrieEntry[] result)
This is equivalent to the other selectR() method but without
its overhead because we're selecting only one best matching
Entry from the Trie.
|
private boolean |
selectR(PatriciaTrie.TrieEntry<K,V> h,
int bitIndex,
K key,
int keyLength,
Trie.Cursor<? super K,? super V> cursor,
PatriciaTrie.TrieEntry[] result) |
int |
size()
Returns the number items in the Trie
|
SortedMap<K,V> |
subMap(K fromKey,
K toKey) |
private PatriciaTrie.TrieEntry<K,V> |
subtree(K prefix,
int offset,
int length)
Finds the subtree that contains the prefix.
|
SortedMap<K,V> |
tailMap(K fromKey) |
String |
toString()
Returns each entry as a string.
|
Map.Entry<K,V> |
traverse(Trie.Cursor<? super K,? super V> cursor)
Traverses the Trie in lexicographical order.
|
private static boolean |
valEquals(Object o1,
Object o2)
Test two values for equality.
|
Collection<V> |
values()
Returns a collection view of the values contained in this map.
|
clone, equals, hashCode, putAll
private static final long serialVersionUID
private final PatriciaTrie.TrieEntry<K,V> root
private int size
private transient int modCount
private final PatriciaTrie.KeyAnalyzer<? super K> keyAnalyzer
private transient volatile Set<K> keySet
private transient volatile Collection<V> values
public PatriciaTrie(PatriciaTrie.KeyAnalyzer<? super K> keyAnalyzer)
public PatriciaTrie.KeyAnalyzer<? super K> getKeyAnalyzer()
public Comparator<? super K> comparator()
comparator
in interface SortedMap<K,V>
public void clear()
public boolean isEmpty()
public int size()
private void incrementSize()
private void decrementSize()
private void incrementModCount()
public V put(K key, V value)
private PatriciaTrie.TrieEntry<K,V> addEntry(PatriciaTrie.TrieEntry<K,V> toAdd, int keyLength)
public V get(Object k)
PatriciaTrie.TrieEntry<K,V> getEntry(Object k)
private PatriciaTrie.TrieEntry<K,V> getNearestEntryForKey(K key, int keyLength)
public V select(K key)
private boolean selectR(PatriciaTrie.TrieEntry<K,V> h, int bitIndex, K key, int keyLength, PatriciaTrie.TrieEntry[] result)
public Map.Entry<K,V> select(K key, Trie.Cursor<? super K,? super V> cursor)
Trie
Cursor.SelectStatus.EXIT
.Cursor.SelectStatus.CONTINUE
to
continue traversing.Cursor.SelectStatus.REMOVE_AND_EXIT
is used to remove the current element
and stop traversing.
Note: The Trie.Cursor.SelectStatus.REMOVE
operation is not supported.
private boolean selectR(PatriciaTrie.TrieEntry<K,V> h, int bitIndex, K key, int keyLength, Trie.Cursor<? super K,? super V> cursor, PatriciaTrie.TrieEntry[] result)
public SortedMap<K,V> getPrefixedBy(K key)
getPrefixedBy
in interface Trie<K,V>
key
- public SortedMap<K,V> getPrefixedBy(K key, int length)
getPrefixedBy
in interface Trie<K,V>
key
- length
- public SortedMap<K,V> getPrefixedBy(K key, int offset, int length)
getPrefixedBy
in interface Trie<K,V>
key
- offset
- length
- public SortedMap<K,V> getPrefixedByBits(K key, int bitLength)
getPrefixedByBits
in interface Trie<K,V>
key
- bitLength
- private SortedMap<K,V> getPrefixedByBits(K key, int offset, int length)
key
- offset
- length
- public boolean containsKey(Object k)
containsKey
in interface Map<K,V>
containsKey
in class AbstractMap<K,V>
public boolean containsValue(Object o)
containsValue
in interface Map<K,V>
containsValue
in class AbstractMap<K,V>
public V remove(Object k)
private V removeEntry(PatriciaTrie.TrieEntry<K,V> h)
private void removeExternalEntry(PatriciaTrie.TrieEntry<K,V> h)
private void removeInternalEntry(PatriciaTrie.TrieEntry<K,V> h)
private PatriciaTrie.TrieEntry<K,V> previousEntry(PatriciaTrie.TrieEntry<K,V> start)
start
- private PatriciaTrie.TrieEntry<K,V> nextEntry(PatriciaTrie.TrieEntry<K,V> node)
private PatriciaTrie.TrieEntry<K,V> nextEntryInSubtree(PatriciaTrie.TrieEntry<K,V> node, PatriciaTrie.TrieEntry<K,V> parentOfSubtree)
private PatriciaTrie.TrieEntry<K,V> nextEntryImpl(PatriciaTrie.TrieEntry<K,V> start, PatriciaTrie.TrieEntry<K,V> previous, PatriciaTrie.TrieEntry<K,V> tree)
public String toString()
toString
in class AbstractMap<K,V>
public Map.Entry<K,V> traverse(Trie.Cursor<? super K,? super V> cursor)
Trie
Cursor.select
will be called on each entry.
The traversal will stop when the cursor returns Cursor.SelectStatus.EXIT
.
Cursor.SelectStatus.CONTINUE
is used to continue traversing.
Cursor.SelectStatus.REMOVE
is used to remove the element that was
selected and continue traversing.
Cursor.SelectStatus.REMOVE_AND_EXIT
is used to remove the current element
and stop traversing.
private boolean isValidUplink(PatriciaTrie.TrieEntry<K,V> next, PatriciaTrie.TrieEntry<K,V> from)
private static boolean isValidBitIndex(int bitIndex)
private static boolean isNullBitKey(int bitIndex)
private static boolean isEqualBitKey(int bitIndex)
private boolean isBitSet(K key, int keyLength, int bitIndex)
private int bitIndex(K key, K foundKey)
Iterator<K> newKeyIterator()
Iterator<V> newValueIterator()
Iterator<Map.Entry<K,V>> newEntryIterator()
public Set<K> keySet()
Iterator.remove
,
Set.remove
, removeAll
, retainAll
, and
clear
operations. It does not support the add
or
addAll
operations.public Collection<V> values()
Iterator.remove
, Collection.remove
,
removeAll
, retainAll
, and clear
operations.
It does not support the add
or addAll
operations.private static boolean valEquals(Object o1, Object o2)
private PatriciaTrie.TrieEntry<K,V> firstEntry()
private PatriciaTrie.TrieEntry<K,V> followLeft(PatriciaTrie.TrieEntry<K,V> node)
private PatriciaTrie.TrieEntry<K,V> lastEntry()
This is implemented by going always to the right until we encounter a valid uplink. That uplink is the last key.
protected PatriciaTrie.TrieEntry<K,V> followRight(PatriciaTrie.TrieEntry<K,V> node)
protected PatriciaTrie.TrieEntry<K,V> higherEntry(K key)
protected PatriciaTrie.TrieEntry<K,V> ceilingEntry(K key)
protected PatriciaTrie.TrieEntry<K,V> lowerEntry(K key)
protected PatriciaTrie.TrieEntry<K,V> floorEntry(K key)
private PatriciaTrie.TrieEntry<K,V> subtree(K prefix, int offset, int length)