The trie-based container has the following declaration:
template< typename Key, typename Mapped, typename Cmp_Fn = std::less<Key>, typename Tag = pat_trie_tag, template< typename Const_Node_Iterator, typename Node_Iterator, typename E_Access_Traits_, typename Allocator_> class Node_Update = null_trie_node_update, typename Allocator = std::allocator<char> > class trie;
The parameters have the following meaning:
The Tag parameter specifies which underlying data structure to use. Instantiating it by pat_trie_tag, specifies an underlying PATRICIA trie (explained shortly); any other tag is currently illegal.
Following is a description of a (PATRICIA) trie (pb_ds follows specifically [okasaki98mereable] and [filliatre2000ptset]).
A (PATRICIA) trie is similar to a tree, but with the following differences:
Element-Access Traits shows an example of such a trie.
A (PATRICIA) trie has some useful properties:
(We would like to thank Matt Austern for the suggestion to include tries.)
A trie inherently views its keys as sequences of elements. For example, a trie can view a string as a sequence of characters. A trie needs to map each of n elements to a number in {0, n - 1}. For example, a trie can map a character c to static_cast<size_t>(c).
Seemingly, then, a trie can assume that its keys support (const) iterators, and that the value_type of this iterator can be cast to a size_t. There are several reasons, though, to decouple the mechanism by which the trie accesses its keys' elements from the trie:
trie is, consequently, parametrized by E_Access_Traits - traits which instruct how to access sequences' elements. string_trie_e_access_traits is a traits class for strings. Each such traits define some types, e.g.,
typename E_Access_Traits::const_iterator
is a const iterator iterating over a key's elements. The traits class must also define methods for obtaining an iterator to the first and last element of a key.
Figure A PATRICIA trie shows a (PATRICIA) trie resulting from inserting the words: "I wish that I could ever see a poem lovely as a trie" (which, unfortunately, does not rhyme).
The leaf nodes contain values; each internal node contains two typename E_Access_Traits::const_iterator objects, indicating the maximal common prefix of all keys in the sub-tree. For example, the shaded internal node roots a sub-tree with leafs "a" and "as". The maximal common prefix is "a". The internal node contains, consequently, to const iterators, one pointing to 'a', and the other to 's'.
Trie-based containers support node invariants, as do tree-based containers (see Tree-Based Containers::Node Invariants). There are two minor differences, though, which, unfortunately, thwart sharing them sharing the same node-updating policies:
Figure A trie and its update policy shows the scheme, as well as some predefined policies (which are explained below).
pb_ds offers the following pre-defined trie node updating policies:
Trie-based containers support split and join methods; the rationale is equal to that of tree-based containers supporting these methods (see Tree-Based Containers::Additional Methods).