Boost C++ 库

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb SutterAndrei Alexandrescu, C++ 编码标准

PrevUpHomeNext

侵入式 Treap 关联容器:treap_set、treap_multiset 和 treap

treap_set、treap_multiset 和 treap 容器
基于 Treap 的侵入式容器的异常安全性
示例

名称 treaptree(树)和 heap(堆)的混合,表示 Treap 兼具二叉搜索树和堆的特性。Treap 是一种二叉搜索树,它按键值和优先级属性对节点进行排序。节点的排序方式使键值形成二叉搜索树,而优先级则遵循最大堆顺序属性。

如果优先级是非随机的,树通常会变得不平衡;这种较差的理论平均情况行为可能会被更好的预期情况行为所抵消,因为最重要的项目将靠近根节点。这意味着最重要的对象将比不太重要的项目更快地检索,并且对于具有相等键值的项目,最重要的对象将首先被找到。这些属性对于某些应用非常重要。

优先级比较将像键值比较一样提供,通过一个函数对象,该对象将存储在侵入式容器中。这意味着优先级可以存储在要引入到 treap 中的值中,或者在运行时计算(通过哈希或类似方法)。

Boost.Intrusive 提供了 3 种基于 treap 的容器:treap_settreap_multisettreap。前两个类似于 setmultiset,而后者是一个泛化,提供了插入唯一键和多个键的功能。

这些容器使用 Boost.Intrusive 钩子的内存开销是 3 个指针。

一个空的 treap_settreap_multisettreap 也具有 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 的容器提供与其他基于树的容器完全相同的保证。
  • 如果优先级顺序仿函数抛出异常,则基于 treap 的容器提供强保证。

现在让我们看一个使用二叉搜索树钩子和 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;
}

PrevUpHomeNext