PBDS
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 了)
- pairing heap
- binomial heap
- redundent-counter binomial heap
- thin heap
后面我们会逐一复习和学习这些数据结构的复杂性。下面是一个使用 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.
太深奥了,看不懂啊。 顺便请教一下博主,有没有关于几何运算的库啊,轻量级的,比如能够计算空间直线 与某个多面体是否相交啊之类的,谢谢。
mvker
2011/05/24 at 9:10 AM
这个不大清楚啊
你说的这个是 graphics 还是 computational geometry 里面的问题啊?
zt
2011/05/26 at 9:43 AM
geometry,偏向于图形学计算的,不是图像方面的。
mvker
2011/05/27 at 1:11 PM
That was very scholarly piece of writing…
Video Capture Device
2011/12/12 at 2:51 AM
[...] policy 的应用,我们后面也讨论过 g++ 中提供的额外的数据结构 PBDS,这就是利用这类思想编写的库。这里记录一些在 Modern C++ Design [...]
policy-based class design « demonstrate 的 blog
2012/02/22 at 9:14 PM