...one of the most highly regarded and expertly designed C++ library projects in the world.
— Herb Sutter 和 Andrei Alexandrescu, C++ 编码标准
名称 treap 是 tree(树)和 heap(堆)的混合,表示 Treap 兼具二叉搜索树和堆的特性。Treap 是一种二叉搜索树,它按键值和优先级属性对节点进行排序。节点的排序方式使键值形成二叉搜索树,而优先级则遵循最大堆顺序属性。
如果优先级是非随机的,树通常会变得不平衡;这种较差的理论平均情况行为可能会被更好的预期情况行为所抵消,因为最重要的项目将靠近根节点。这意味着最重要的对象将比不太重要的项目更快地检索,并且对于具有相等键值的项目,最重要的对象将首先被找到。这些属性对于某些应用非常重要。
优先级比较将像键值比较一样提供,通过一个函数对象,该对象将存储在侵入式容器中。这意味着优先级可以存储在要引入到 treap 中的值中,或者在运行时计算(通过哈希或类似方法)。
Boost.Intrusive 提供了 3 种基于 treap 的容器:treap_set
、treap_multiset
和 treap
。前两个类似于 set
或 multiset
,而后者是一个泛化,提供了插入唯一键和多个键的功能。
这些容器使用 Boost.Intrusive 钩子的内存开销是 3 个指针。
一个空的 treap_set
、treap_multiset
或 treap
也具有 3 个指针和一个整数的大小(假设键值和优先级比较的函数对象为空,并且大小为常数时间)。
Boost.Intrusive Treap 关联容器不使用它们自己的钩子类型,而是使用普通的二叉搜索树钩子。有关这些钩子的更多信息,请参阅 二叉搜索树钩子:bs_set_base_hook 和 bs_set_member_hook 部分。
template <class T, class ...Options> class treap_set; template <class T, class ...Options> class treap_multiset; template <class T, class ...Options> class treap;
这些容器接收与 如何使用 Boost.Intrusive 部分中解释的相同的选项
base_hook<class Hook>
/ member_hook<class T, class Hook, Hook T::* PtrToMember>
/ value_traits<class ValueTraits>
:指定用于配置容器的钩子类型或值特征。(要了解值特征,请转到 具有自定义 ValueTraits 的容器 部分。)constant_time_size<bool Enabled>
:激活常数时间 size()
操作。默认值:constant_time_size<true>
size_type<typename SizeType>
:指定将用于存储容器大小的类型。默认值:size_type<std::size_t>
它们还可以接收其他选项
compare<class Compare>
:用于比较要插入容器的对象的比较函数。比较仿函数必须引起严格弱排序。默认值:compare< std::less<key_type> >
priority_of_value<class PriorityOfValue>
:一个函数对象,指定 treap 容器的优先级类型(priority_type
)以及从值类型获取优先级的运算符。默认值:priority_type
等于 value_type
(类似 set 的接口)。priority<class PriorityCompare>
:用于比较要插入容器的对象的优先级比较函数。比较仿函数必须引起严格弱排序。默认值:priority< priority_compare<priority_type> >
key_of_value<class KeyOfValueFunctionObject>
:一个函数对象,用于定义要存储的值类型的 key_type
。此类型将允许类似 map 的接口。有关详细信息,请参阅 具有 set 和 multiset 的 Map 和 multimap 类接口。默认值:key_type
等于 value_type
(类似 set 的接口)。默认的 priority_compare<T>
对象函数将调用一个非限定函数 priority_order
,传递两个常量 T
引用作为参数,并且如果第一个参数具有更高的优先级(它将被更快地搜索)则应返回 true,从而引起严格弱排序。该函数将使用 ADL 查找找到,以便用户只需在与类相同的命名空间中定义一个 priority_order
函数
struct MyType { friend bool priority_order(const MyType &a, const MyType &b) {...} };
或
namespace mytype { struct MyType{ ... }; bool priority_order(const MyType &a, const MyType &b) {...} } //namespace mytype {
通常,侵入式容器提供强大的安全保证,但 treap 容器必须处理两个可能抛出异常的仿函数(一个用于值排序,另一个用于优先级排序)。此外,treap 删除操作需要基于优先级顺序函数进行旋转,并且此问题会降低通常的 erase(const_iterator)
无抛出保证。但是,intrusive 在这些情况下提供了尽可能强的行为。总结如下
现在让我们看一个使用二叉搜索树钩子和 treap_set
/ treap_multiset
容器的小例子
#include <boost/intrusive/treap_set.hpp> #include <vector> #include <functional> #include <cassert> using namespace boost::intrusive; class MyClass : public bs_set_base_hook<> //This is a base hook { int int_; unsigned int prio_; public: //This is a member hook bs_set_member_hook<> member_hook_; MyClass(int i, unsigned int prio) : int_(i), prio_(prio) {} unsigned int get_priority() const { return this->prio_; } //Less and greater operators 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_; } //Default priority compare friend bool priority_order (const MyClass &a, const MyClass &b) { return a.prio_ < b.prio_; } //Lower value means higher priority //Inverse priority compare friend bool priority_inverse_order (const MyClass &a, const MyClass &b) { return a.prio_ > b.prio_; } //Higher value means higher priority }; struct inverse_priority { bool operator()(const MyClass &a, const MyClass &b) const { return priority_inverse_order(a, b); } }; //Define an treap_set using the base hook that will store values in reverse order typedef treap_set< MyClass, compare<std::greater<MyClass> > > BaseSet; //Define an multiset using the member hook that will store typedef member_hook<MyClass, bs_set_member_hook<>, &MyClass::member_hook_> MemberOption; typedef treap_multiset < MyClass, MemberOption, priority<inverse_priority> > MemberMultiset; int main() { typedef std::vector<MyClass>::iterator VectIt; //Create several MyClass objects, each one with a different value std::vector<MyClass> values; for(std::size_t i = 0; i < 100u; ++i) values.push_back(MyClass((int)i, unsigned(i % 10))); BaseSet baseset; MemberMultiset membermultiset; //Now insert them in the sets for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){ baseset.insert(*it); membermultiset.insert(*it); } //Now test treap_sets { BaseSet::reverse_iterator rbit(baseset.rbegin()); MemberMultiset::iterator mit(membermultiset.begin()); VectIt it(values.begin()), itend(values.end()); //Test the objects inserted in the base hook treap_set for(; it != itend; ++it, ++rbit) if(&*rbit != &*it) return 1; //Test the objects inserted in the member hook treap_set for(it = values.begin(); it != itend; ++it, ++mit) if(&*mit != &*it) return 1; //Test priority order for(int i = 0; i < 100; ++i){ if(baseset.top()->get_priority() != static_cast<unsigned int>(i/10)) return 1; if(membermultiset.top()->get_priority() != 9u - static_cast<unsigned int>(i/10)) return 1; baseset.erase(baseset.top()); membermultiset.erase(membermultiset.top()); } } return 0; }