C++ associative containers are usually based on red-black tree implementations
(e.g.: STL, Boost.Intrusive associative containers). However, there are other
interesting data structures that offer some advantages (and also disadvantages).

Splay trees are self-adjusting binary search trees used typically in caches,
memory allocators and other applications, because splay trees have a "caching
effect": recently accessed elements have better access times than elements
accessed less frequently. For more information on splay trees see Wikipedia
entry.

Boost.Intrusive offers 3 containers based
on splay trees: splay_set,
splay_multiset
and splaytree. The
first two are similar to set
or multiset and the
latter is a generalization that offers functions both to insert unique and
multiple keys.

The memory overhead of these containers with Boost.Intrusive hooks is usually
3 pointers. An empty, non constant-time size splay container has also a size
of 3 pointers.

Splay tree based intrusive containers have logarithmic complexity in many
operations like searches, insertions, erasures, etc., but if some elements
are more frequently accessed than others, splay trees perform faster searches
than equivalent balanced binary trees (such as red-black trees).

The caching effect offered by splay trees comes with a cost: the tree must
be rebalanced when an element is searched. This disallows const versions
of search functions like find(), lower_bound(), upper_bound(), equal_range(), count(), etc.

Because of this, splay-tree based associative containers are not drop-in
replacements of set/
multiset.

Apart from this, if element searches are randomized, the tree will be rebalanced
without taking advantage of the cache effect, so splay trees can offer worse
performance than other balanced trees for some search patterns.

base_hook<classHook>
/ member_hook<classT,classHook,HookT::*PtrToMember>
/ value_traits<classValueTraits>:
To specify the hook type or value traits used to configure the container.
(To learn about value traits go to the section Containers
with custom ValueTraits.)

Intrusive splay containers can also use plain binary search tree hooks bs_set_base_hook and
bs_set_base_hook.
These hooks can be used by other intrusive containers like intrusive scapegoat
containers sg_set and
sg_multiset. A
programmer might prefer using a binary search tree hook so that the same
type can be inserted in some situations in a splay container but also inserted
in other compatible containers when the hook is not being used in a splay
container.

Now let's see a small example using both splay hooks, binary search tree
hooks and splay_set/
splay_multiset
containers:

#include<boost/intrusive/splay_set.hpp>#include<boost/intrusive/bs_set_hook.hpp>#include<vector>#include<algorithm>usingnamespaceboost::intrusive;classMyClass:publicsplay_set_base_hook<>//This is an splay tree base hook,publicbs_set_base_hook<>//This is a binary search tree base hook{intint_;public://This is a member hooksplay_set_member_hook<>member_hook_;MyClass(inti):int_(i){}friendbooloperator<(constMyClass&a,constMyClass&b){returna.int_<b.int_;}friendbooloperator>(constMyClass&a,constMyClass&b){returna.int_>b.int_;}friendbooloperator==(constMyClass&a,constMyClass&b){returna.int_==b.int_;}};//Define a set using the base hook that will store values in reverse ordertypedefsplay_set<MyClass,compare<std::greater<MyClass>>>BaseSplaySet;//Define a set using the binary search tree hooktypedefsplay_set<MyClass,base_hook<bs_set_base_hook<>>>BaseBsSplaySet;//Define an multiset using the member hooktypedefmember_hook<MyClass,splay_set_member_hook<>,&MyClass::member_hook_>MemberOption;typedefsplay_multiset<MyClass,MemberOption>MemberSplayMultiset;intmain(){typedefstd::vector<MyClass>::iteratorVectIt;typedefstd::vector<MyClass>::reverse_iteratorVectRit;//Create several MyClass objects, each one with a different valuestd::vector<MyClass>values;for(inti=0;i<100;++i)values.push_back(MyClass(i));BaseSplaySetbaseset;BaseBsSplaySetbsbaseset;MemberSplayMultisetmembermultiset;//Insert values in the containerfor(VectItit(values.begin()),itend(values.end());it!=itend;++it){baseset.insert(*it);bsbaseset.insert(*it);membermultiset.insert(*it);}//Now test sets{BaseSplaySet::reverse_iteratorrbit(baseset.rbegin()),rbitend(baseset.rend());BaseBsSplaySet::iteratorbsit(bsbaseset.begin()),bsitend(bsbaseset.end());MemberSplayMultiset::iteratormit(membermultiset.begin()),mitend(membermultiset.end());VectItit(values.begin()),itend(values.end());//Test the objects inserted in the base hook setfor(;it!=itend;++it,++rbit){if(&*rbit!=&*it)return1;}//Test the objects inserted in member and binary search hook setsfor(it=values.begin();it!=itend;++it,++bsit,++mit){if(&*bsit!=&*it)return1;if(&*mit!=&*it)return1;}}return0;}