![]() |
Home | Libraries | People | FAQ | More |
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_multiset 和 splaytree。前兩種類似於 set 或 multiset,而最後一種則是一個提供了插入唯一鍵和重複鍵功能的泛型。
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_multiset 和 splaytree 共享相同的鉤子。
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_hook 和 splay_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_hook 和
bs_set_base_hook。這些鉤子可以被其它介入式容器使用,如介入式 scapegoat
容器 sg_set 和
sg_multiset。程序員可能更喜歡使用二分查找樹鉤子,這樣同一個類型可以在某些情況下插入到 splay 容器中,當這些鉤子不是在 splay 容器中使用時,也可以插入到其它兼容的容器中。
bs_set_base_hook
and bs_set_member_hook
admit the same options as splay_set_base_hook.bs_set_base_hook 和 bs_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; }