红魔咖啡馆

头发越掉越多,头发越掉越少

0%

【数据结构】pb_ds库

使用方法

引入头文件,有万能头用:

1
#include <bits/extc++.h>

pb_ds的容器和算法定义在另外两个命名空间中,而非std:

1
2
using namespace __gnu_cxx;
using namespace __gnu_pbds;

哈希表

pb_ds中有两种哈希表:

1
2
__gnu_pbds::gp_hash_table <T1, T2> h1;
__gnu_pbds::cc_hash_table <T1, T2> h2;

前者为探察法解决哈希冲突,速度更快,一般使用第一个

后者为拉链法解决哈希冲突,速度更慢,比umap还慢

pb_ds中的哈希表很快,比map和umap还要快,且更难被hack

支持pair

一般的哈希表不能以pair作为key值,我们需要显式的template重载一下hash

1
2
3
4
5
6
7
template <class T1, class T2> 
struct std::tr1::hash <std::pair <T1, T2> > {
    size_t operator() (std::pair <T1, T2> x) const {
        std::tr1::hash <T1> H1; std::tr1::hash <T2> H2;
        return H1(x.first) ^ H2(x.second); // 自定义的 hash 函数
    }
};

平衡树

哈希表的定义如下:

1
2
3
__gnu_pbds::tree<Key, Mapped, Cmp_Fn = std::less<Key>, Tag = rb_tree_tag,
                 Node_Update = null_tree_node_update,
                 Allocator = std::allocator<char>>

其中模板的形参意思为:

  • Key:储存的元素类型,如果要存储多个相同的Key元素,则需要使用类似于pair和struct方法,并配合使用lower_bound和upper_bound成员函数查找
  • Mapped:映射规则类型,若指示关联容器是集合,类似set,则填入null_type,若是带值的集合,类似于map,则填入类似std::map<Key, Value>的值类型
  • Cmp_Fn:关键字比较函子,如std::less<Key>
  • Tag:选择使用何种底层数据类型,默认是rb_tree_tag,库里提供了三种不同平衡树:
    • rb_tree_tag:红黑树,一般用这个
    • splay_tree_tag:splay树
    • ov_tree_tag:有序向量树
  • Node_Update:更新节点策略,默认使用null_node_update,如果想使用order_of_keyfind_by_order方法,需要使用tree_order_statistics_node_update
  • Allocator:空间分配器类型

构造方式

1
2
3
4
__gnu_pbds::tree<std::pair<int, int>, __gnu_pbds::null_type,
                 std::less<std::pair<int, int>>, __gnu_pbds::rb_tree_tag,
                 __gnu_pbds::tree_order_statistics_node_update>
    tr;

成员函数

  • insert(x):树中插入一个元素
  • erase(x):从树中删除一个元素/迭代器,若x是迭代器,则返回指向下一个的迭代器;如果x是key,则返回是否删除成功
  • order_of_key(x):返回严格小于x的元素个数,即从0开始的排名
  • lower_bound(x):返回第一个不小于x的元素所对应的迭代器
  • upper_bound(x):返回第一个严格大于x的元素所对应的迭代器
  • join(x):将x树并入当前数,x树清空(保证比较函数和元素类型相同)
  • split(x,b):以Cmp_Fn比较,小于等于x的属于当前树,其余的属于b树
  • empty():返回是否为空
  • size():返回大小