Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Intrusive splay tree based associative containers: splay_set, splay_multiset and , splay_tree 

基於 splay 樹的介入式關聯容器:splay_set, splay_multiset 和 splay_tree 

Advantages and disadvantages of splay tree based containers 基於 splay 樹的容器的優缺點
splay_set, splay_multiset and splaytree hooks  splay_set, splay_multiset 和 splaytree 鉤子
splay_set, splay_multiset and splaytree containers  splay_set, splay_multiset 和 splaytree 容器
Splay trees with BST hooks 帶 BST 鉤子的 splay 樹
Example 例子

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)
C++關聯容器通常都是基於紅黑樹來實現的(如:STL, Boost.Intrusive 關聯容器)。但是,還有其它的有趣的數據結構可以提供一些優點(也有缺點)。

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.
Splay 樹是一種自調整的二分查找樹,通常用於緩存、內存分配器和其它應用程序,因為 splay 樹具有一種 "緩存效果":最近訪問的元素比較少訪問的元素具有更好的訪問時間。有關 splay 樹的更多信息,請見 Wikipedia 相關條目

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.
Boost.Intrusive 提供了3種基於 splay 樹的容器:splay_set, splay_multisetsplaytree。前兩種類似於 setmultiset,而最後一種則是一個提供了插入唯一鍵和重複鍵功能的泛型。

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.
這些帶有 Boost.Intrusive 鉤子的容器的空間開銷通常為3個指針。一個空的、不帶常量時間 size 的 splay 容器也具有3個指針的大小。

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).
基於 Splay 樹的介入式容器的多數操作具有對數複雜度,如查找、插入、刪除等等,但是如果有些元素比較其它元素的使用更為頻繁,那麼 splay 樹可以提供比同等的平衡二叉樹(如紅黑樹)更快的查找速度。

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.
splay 樹所提供的緩存效果是有代價的:在查找元素時,該樹必須被重新平衡。這樣就禁止了查找函數的常量版本,如 find(), lower_bound(), upper_bound(), equal_range(), count() 等等。

Because of this, splay-tree based associative containers are not drop-in replacements of set/ multiset.
因此,基於 splay 樹的關聯容器不能替代 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.
除此之外,如果元素的查找是隨機的,那麼該樹既要進行重新平衡,又得不到緩存效果的好處,所以 splay 樹對於這種查找模式將提供比其它平衡樹更差的性能。

splay_set, splay_multiset and splaytree share the same hooks.
splay_set, splay_multisetsplaytree 共享相同的鉤子。

template <class ...Options>
class splay_set_base_hook;
  • splay_set_base_hook: the user class derives publicly from this class to make it compatible with splay tree based containers.
    splay_set_base_hook: 用戶類公有派生自此類以兼容於基於 splay 樹的容器。

template <class ...Options>
class splay_set_member_hook;
  • set_member_hook: the user class contains a public member of this class to make it compatible with splay tree based containers.
    set_member_hook: 用戶類包含一個此類的公有成員以兼容於基於 splay 樹的容器。

splay_set_base_hook and splay_set_member_hook receive the same options explained in the section How to use Boost.Intrusive:
splay_set_base_hooksplay_set_member_hook 接受在 如何使用 Boost.Intrusive 一節中說明的各種選項: 

  • tag<class Tag> (for base hooks only): This argument serves as a tag, so you can derive from more than one base hook. Default: tag<default_tag>.
    tag<class Tag> (只用於基類鉤子):該參數作為一個標記,你可以派生自多個 slist 鉤子。缺省值:tag<default_tag>.
  • link_mode<link_mode_type LinkMode>: The linking policy. Default: link_mode<safe_link>.
    link_mode<link_mode_type LinkMode>: 鏈接策略。缺省值:link_mode<safe_link>.
  • void_pointer<class VoidPointer>: The pointer type to be used internally in the hook and propagated to the container. Default: void_pointer<void*>.
    void_pointer<class VoidPointer>: 在鉤子內部使用並被傳遞給容器的指針類型。缺省值:void_pointer<void*>.

template <class T, class ...Options>
class splay_set;

template <class T, class ...Options>
class splay_multiset;

template <class T, class ...Options>
class splaytree;

These containers receive the same options explained in the section How to use Boost.Intrusive:
這些容器接受在 如何使用 Boost.Intrusive 一節中說明的選項:

  • base_hook<class Hook> / member_hook<class T, class Hook, Hook T::* PtrToMember> / value_traits<class ValueTraits>: 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.)
    base_hook<class Hook> / member_hook<class T, class Hook, Hook T::* PtrToMember> / value_traits<class ValueTraits>: 指定用於配置容器的鉤子類型或 value traits。(要學習有關 value traits 的知識,請見 帶定制化 ValueTraits 的容器)
  • constant_time_size<bool Enabled>: To activate the constant-time size() operation. Default: constant_time_size<true>
    constant_time_size<bool Enabled>: 激活常量時間的 size() 操作。缺省值:constant_time_size<true>
  • size_type<bool Enabled>: To specify the type that will be used to store the size of the container. Default: size_type<std::size_t>
    size_type<bool Enabled>: 指定用於保存容器大小的類型。缺省值:size_type<std::size_t>.

And they also can receive an additional option:
它們還可以接受其它選項:

  • compare<class Compare>: Comparison function for the objects to be inserted in containers. The comparison functor must induce a strict weak ordering. Default: compare< std::less<T> >
    compare<class Compare>: 被插入到容器中的對象所用的比較函數。這個比較函數必須實現一個嚴格弱序。缺省值:compare< std::less<T> >

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.
介入式 splay 容器也可以使用普通的二分查找樹鉤子 bs_set_base_hookbs_set_base_hook。這些鉤子可以被其它介入式容器使用,如介入式 scapegoat 容器 sg_setsg_multiset。程序員可能更喜歡使用二分查找樹鉤子,這樣同一個類型可以在某些情況下插入到 splay 容器中,當這些鉤子不是在 splay 容器中使用時,也可以插入到其它兼容的容器中。

bs_set_base_hook and bs_set_member_hook admit the same options as splay_set_base_hook.
bs_set_base_hookbs_set_member_hook 接受與 splay_set_base_hook 相同的選項。

Now let's see a small example using both splay hooks, binary search tree hooks and splay_set/ splay_multiset containers:
現在我們來看一個使用 splay 鉤子、二分查找樹鉤子和 splay_set/ splay_multiset 容器的小例子:

#include <boost/intrusive/splay_set.hpp>
#include <boost/intrusive/bs_set_hook.hpp>
#include <vector>
#include <algorithm>

using namespace boost::intrusive;

class MyClass
   : public splay_set_base_hook<>   //This is an splay tree base hook
, public bs_set_base_hook<> //This is a binary search tree base hook

{ int int_; public: //This is a member hook
splay_set_member_hook<> member_hook_; MyClass(int i) : int_(i) {} friend bool operator< (const MyClass &a, const MyClass &b) { return a.int_ < b.int_; } friend bool operator> (const MyClass &a, const MyClass &b) { return a.int_ > b.int_; } friend bool operator== (const MyClass &a, const MyClass &b) { return a.int_ < b.int_; } }; //Define a set using the base hook that will store values in reverse order
typedef splay_set< MyClass, compare<std::greater<MyClass> > > BaseSplaySet; //Define a set using the binary search tree hook
typedef splay_set< MyClass, base_hook<bs_set_base_hook<> > > BaseBsSplaySet; //Define an multiset using the member hook
typedef member_hook<MyClass, splay_set_member_hook<>, &MyClass::member_hook_> MemberOption; typedef splay_multiset< MyClass, MemberOption> MemberSplayMultiset; int main() { typedef std::vector<MyClass>::iterator VectIt; typedef std::vector<MyClass>::reverse_iterator VectRit; //Create several MyClass objects, each one with a different value
std::vector<MyClass> values; for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); BaseSplaySet baseset; BaseBsSplaySet bsbaseset; MemberSplayMultiset membermultiset; //Insert values in the container
for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){ baseset.insert(*it); bsbaseset.insert(*it); membermultiset.insert(*it); } //Now test sets
{ BaseSplaySet::reverse_iterator rbit(baseset.rbegin()), rbitend(baseset.rend()); BaseBsSplaySet::iterator bsit(bsbaseset.begin()), bsitend(bsbaseset.end()); MemberSplayMultiset::iterator mit(membermultiset.begin()), mitend(membermultiset.end()); VectIt it(values.begin()), itend(values.end()); //Test the objects inserted in the base hook set
for(; it != itend; ++it, ++rbit){ if(&*rbit != &*it) return 1; } //Test the objects inserted in member and binary search hook sets
for(it = values.begin(); it != itend; ++it, ++bsit, ++mit){ if(&*bsit != &*it) return 1; if(&*mit != &*it) return 1; } } return 0; }


PrevUpHomeNext