pb_ds库简述

为了区分STL和pb_ds库中的容器和函数, 该篇博文中所有出现的类 / 函数 / 方法等, 均将在前面加上名称空间名(namespace).

一. 绪言

众所周知, C++有STL(Standard Template Library). STL中包含了非常多的容器(Containers)和容器适配器(Container Adaptors), 这里稍微地不完全地列举一下(包括他们的中文名):

Containers 容器:

Sequence containers 线性容器:

Associative containers 关联容器:

Container Adaptors 容器适配器:

这些DS(Data Structures), 不管是打ACM, 还是平时编码, 出现的频率都是非常高的.
原因还是要归功与C++的模板及元能力, 给容器提供了泛型(genericity). STL中对各种DS的封装, 给我们省去了很多构建基础DS的时间.

但是, 实际在使用STL时, 会感觉到很多功能受限. 比如STL中提供的堆容器, 只是最最基础的堆,

// Defined in header <queue>
template<
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>
> class priority_queue;

并没有任何可扩展性. 比如在某些情况下需要高效地合并两个堆的时候, 使用STL提供的std::priority_queue::push方法

// std::priority_queue::push
void push( const value_type& value );
void push( value_type&& value ); // (since C++11)

将显得非常的低效(这种也被叫做”暴力合并”). 对这方面比较了解的同学一定知道, 我这里是在点名可并堆.

另外, 比如STL中没有给我们提供树结构. 虽然set和map的内部是由红黑树(Red-black Tree)实现的, 但是毕竟这两个容器的使用范围比红黑树要狭窄, 我们想要的, 还是有一个最基本的红黑树, 给我们提供快速搜索的功能. 说到搜索, 另外地想到了哈希表(Hash Table), 虽然STL(C++11)给我们提供了hash,

// Defined in header <functional>
template< class Key >
struct hash;  // (Since C++11)

但是其实并没有提供一个现成的哈希表供我们使用, 有些情况下使用起来并不方便.

二. 库简述

gcc给我们提供的pb_ds(Policy-based Data Structures)库被藏在了标准库中比较深的地方,

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>

这其中包含的一些看似方便使用的DS, 如priority_queue(优先队列/堆), hash(哈希), tree(树), trie(字典树), 并不属于C++标准模板库的范畴, 并且他们也是gcc特有的.
因为不属于STL, 使用他们的方法也就不能通过cppreference很轻松地查找到. 前两天我也花了一点时间使用国内外的搜索引擎去搜索有关pb_ds库的内容, 但比较直观的教程实在是屈指可数. 于是最终我选择了直接阅读g++文档和pb_ds的源码, 来直接了解pb_ds的内容. btw, g++也官方给出了一些简单的教程, 这里也将参考.

三. 容器简述

我将在这一部分给出pb_ds库中的一些类的简单描述, 稍后会在各个类独立的文章中给出细节说明和Sample.

更多的内容将放在正式文章中.

四. Policy和Tag相关

暂不明晰. 待补充.

代码来源

上文中出现的代码, 均来自cppreference, libstdc++-api和pb_ds库的源码, 本文仅对原代码的格式进行了细微的调整, 使其更方便阅读.