demonstrate 的 blog

daily blog

PBDS

with 5 comments

policy-based data structure 是 GCC 实现一系列数据结构(容器)的框架。我们看看下面的例子:

#include <iostream>
#include <cassert>
#include <ext/pb_ds/assoc_container.hpp>

using namespace std;
using namespace __gnu_pbds;

template<class Cntnr> void
some_op_sequence(Cntnr& r_c) {
  assert(r_c.empty());
  assert(r_c.size() == 0);

  r_c.insert(make_pair(1, 'a'));

  r_c[2] = 'b';

  assert(!r_c.empty());
  assert(r_c.size() == 2);

  cout << "Key 1 is mapped to " << r_c[1] << endl;
  cout << "Key 2 is mapped to " << r_c[2] << endl;

  cout << endl << "All value types in the container:" << endl;

  typedef typename Cntnr::const_iterator const_iterator;
  for (const_iterator it = r_c.begin(); it != r_c.end(); ++it)
    cout << it->first << " -> " << it->second << endl;
  cout << endl;

  r_c.clear();

  assert(r_c.empty());
  assert(r_c.size() == 0);
}

int
main(int, char**) {
  {
    // Perform operations on a collision-chaining hash map.
    cc_hash_table<int, char> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on a general-probing hash map.
    gp_hash_table<int, char> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on a red-black tree map.
    tree<int, char> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on a splay tree map.
    tree<int, char, less<int>, splay_tree_tag> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on an ov tree map.
    tree<int, char, less<int>, ov_tree_tag> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on a list-update map.
    list_update<int, char> c;
    some_op_sequence(c);
  }
}

这使用了各种 PBDS 用作 map,事实上,我们可以将模版参数中对应的 mapped(即 char)替换成为 null_mapped_type 就变成了对应的 set 容器。

PBDS 提供的数据结构

这 里我们稍微看看 PBDS 里面有哪些数据结构是我们可以直接使用的。PBDS 包括两类数据结构,一种是上面例子中的 associative container(assoc_container<Key, Mapped, Tag, Policy, Allocator>):

  • basic tree 类型(basic_tree_tag,增加了 NodeUpdate<ConstNodeIterator, NodeIterator, CmpFn, Allocator> 模版参数)包括 tree(提供 CmpFn 这个额外的模版参数) 和 trie(提供 ElementAccessTraits 这个模版参数,NodeUpdate 中的 CmpFn 改由 ElementAccessTraits 提供)两种,其中 tree 包括 rb_tree(红黑树)、ov_tree(ordered vector tree,类似于 binary heap 的做法,但是数组满足 tree 的性质)和 splay_tree 的实现;trie 包括 PATRICIA trie(也就是 radix tree)的实现。
  • list update based associative container(提供 EqFn 与 UpdatePolicy)是利用 list 存储 key;
  • basic hash table 是使用 hash 实现的 associative container(提供 HashFn,EqFn,ResizePolicy 和 StoreHash),包括 cc_hash(collision chaining hash table,出现碰撞后就将其 chain 在一起,提供 CombineHashFn)和 gp_hash(general probing hash table,提供 CombineProbeFn 和 ProbeFn)。

另外还提供了优先队列(priority_queue<ValueType, CmpFn, Tag, Allocator>)的实现,包括以下几种(只需更换对应的 tag 就能获得需要的 priority_queue 了)

后面我们会逐一复习和学习这些数据结构的复杂性。下面是一个使用 priority queue 的简单的例子。

#include <cassert>
#include <iostream>
#include <ext/pb_ds/priority_queue.hpp>

using namespace std;
using namespace __gnu_pbds;

template<class Cntnr> void
some_op_sequence(Cntnr& r_c) {
  assert(r_c.empty());
  assert(r_c.size() == 0);

  for (size_t i = 0; i < 10; ++i)
    r_c.push(i);
  cout << endl << "All values in the container:" << endl;

  typedef typename Cntnr::const_iterator const_iterator;
  for (const_iterator it = r_c.begin(); it != r_c.end();  ++it)
    cout <<* it << endl;
  assert(!r_c.empty());
  assert(r_c.size() == 10);

  cout << "Popping all values: " << endl;
  while (!r_c.empty()) {
    cout << r_c.top() << endl;
    r_c.pop();
  }
  assert(r_c.empty());
  assert(r_c.size() == 0);

  cout << endl;
}

int main(int, char**) {
  {
    // Perform operations on a pairing-heap queue.
    cout << "Pairing heap" << endl;
    __gnu_pbds::priority_queue<int, less<int>, pairing_heap_tag> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on a binomial-heap queue.
    cout << "Binomial heap" << endl;
    __gnu_pbds::priority_queue<int, less<int>, binomial_heap_tag> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on a binomial-heap queue.
    cout << "Redundant-counter binomial heap" << endl;
    __gnu_pbds::priority_queue<int, less<int>, rc_binomial_heap_tag> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on a binomial-heap queue.
    cout << "Binary heap" << endl;
    __gnu_pbds::priority_queue<int, less<int>, binary_heap_tag> c;
    some_op_sequence(c);
  }

  {
    // Perform operations on a thin-heap queue.
    cout << "Thin heap" << endl;
    __gnu_pbds::priority_queue<int, less<int>, thin_heap_tag> c;
    some_op_sequence(c);
  }

  return 0;
}

从某种意义上来说 PBDS 似乎给用户一种假象,“可以为所有的容器写 generic function 了”,但是个人感觉却很难在其框架下进行扩展。希望这只是我现在的误解。看到有评测说 PBDS 的 trie 性能并不好,不知道这只是实现算法上的问题还是这个 framework 的问题。按照它自己的说法是希望实现一个高性能的数据结构。

——————
Of every clean beast you shall take to you by sevens, the male and his female: and of beasts that are not clean by two, the male and his female.

Written by zt

2011/05/22 at 8:25 PM

Posted in c/c++

Tagged with ,

5 Responses

Subscribe to comments with RSS.

  1. 太深奥了,看不懂啊。 顺便请教一下博主,有没有关于几何运算的库啊,轻量级的,比如能够计算空间直线 与某个多面体是否相交啊之类的,谢谢。

    mvker

    2011/05/24 at 9:10 AM

  2. 这个不大清楚啊

    你说的这个是 graphics 还是 computational geometry 里面的问题啊?

    zt

    2011/05/26 at 9:43 AM

  3. geometry,偏向于图形学计算的,不是图像方面的。

    mvker

    2011/05/27 at 1:11 PM

  4. That was very scholarly piece of writing…

  5. [...] policy 的应用,我们后面也讨论过 g++ 中提供的额外的数据结构 PBDS,这就是利用这类思想编写的库。这里记录一些在 Modern C++ Design [...]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.