C++ __gnu_pbds(hash,可并堆,平衡树)

pb_ds 是GNU-C++自带的一个C++的扩展库,其中实现了很多数据结构,比STL里面的功能更强大

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>   // 用tree
#include<ext/pb_ds/hash_policy.hpp>   // 用hash
#include<ext/pb_ds/trie_policy.hpp>   // 用trie
#include<ext/pb_ds/priority_queue.hpp>// 用priority_queue
using namespace __gnu_pbds;
---
#include<bits/extc++.h>
using namespace __gnu_pbds;
//bits/extc++.h与bits/stdc++.h类似,bits/extc++.h是所有拓展库,bits/stdc++.h是所有标准库

哈希表

其中cc开头为拉链法,gp开头为探测法,个人实测探测法稍微快一些。

啥?操作?其实就和map差不多,支持[ ]和find。

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;

cc_hash_table<string,int>mp1;//拉链法
gp_hash_table<string,int>mp2;//查探法(快一些)

说明:

在不允许使用C++11的时候,pb_ds库中的两种hash函数比map的效率大大提高 ,可以代替map作为一个哈希工具,使用方法和map完全一样,一般来说查探法的效率更高

可并堆

需要的头文件:

用法和普通的优先队列一样

#include<ext/pb_ds/priority_queue.hpp>
using namespace __gnu_pbds;
__gnu_pbds::priority_queue<int>q;//因为放置和std重复,故需要带上命名空间
__gnu_pbds::priority_queue<int,greater<int>,pairing_heap_tag> q;//最快
__gnu_pbds::priority_queue<int,greater<int>,binary_heap_tag> q;
__gnu_pbds::priority_queue<int,greater<int>,binomial_heap_tag> q;
__gnu_pbds::priority_queue<int,greater<int>,rc_binomial_heap_tag> q;
__gnu_pbds::priority_queue<int,greater<int>,thin_heap_tag> q;
__gnu_pbds::priority_queue<int,greater<int> > q;

pb_ds库的堆提供了五种tag,分别是binary_heap_tagbinomal_heap_tagpairing_heap_tagthin_heap_tagrc_binomal_heap_tag。 因为重名的原因一定要加上 __gnu_pbds::
在这里插入图片描述

常用操作:

push()  //会返回一个迭代器
top()    //同 STL
size()   //同 STL 
empty()  //同 STL 
clear()  //同 STL 
pop()    //同 STL 
join(priority_queue &other)            //合并两个堆,other会被清空
split(Pred prd,priority_queue &other)  //分离出两个堆
modify(point_iterator it,const key)    //修改一个节点的值

平衡树

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>

using namespace __gnu_pbds;
template<typename T>
using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;

// rb_tree_tag 和 splay_tree_tag 选择树的类型(红黑树和伸展树)
T // 自定义数据类型
null_type//无映射(老版本g++为null_mapped_type)
less<T>//Node的排序方式从小到大排序
tree_order_statistics_node_update//参数表示如何更新保存节点信息 tree_order_statistics_node_update会额外获得order_of_key()和find_by_order()两个功能。

ordered_set<Node> Tree;  // Node 自定义struct 注意重载less
Tree.insert(Node);       // 插入
Tree.erase(Node);        // 删除
Tree.order_of_key(Node); // 求Node的排名:当前数小的数的个数 +1
Tree.find_by_order(k);   // 返回排名为k+1的iterator 即有k个Node比*it小
Tree.join(b);            // 将b并入Tree,前提是两棵树类型一致并且二没有重复元素
Tree.split(v, b);        // 分裂,key小于等于v的元素属于Tree,其余属于b
Tree.lower_bound(Node);  // 返回第一个大于等于x的元素的迭代器
Tree.upper_bound(Node);  // 返回第一个大于x的元素的迭代器

//以上的所有操作的时间复杂度均为O(logn)
//注意,插入的元素会去重,如set
ordered_set<T>::point_iterator it=Tree.begin();  // 迭代器
//显然迭代器可以++,--运算
P3369 【模板】普通平衡树

因为tree里不能有相同的数,但是实际会插入相同的数,所以把这些数左移20位在加上一个常数操作( n < 2 20 n<2^{20} n<220,如果 a < b a<b a<b,那么一定有 { ( a < < 20 ) + n } < { b < < 20 } \{(a<<20) +n\}<\{b<<20\} {(a<<20)+n}<{b<<20},这样就保证了在不影响相对大小关系的情况下,消除了相同的数。

别的操作看代码就可以理解了,非常巧妙的搞定了相同数的情况。

rb_tree_tag
#include<bits/stdc++.h>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
using ll=long long;

template <class T=int> T rd()
{
    T res=0;T fg=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}
    while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res*fg;
}
template<typename T>
using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;

const int N=100010;
int n,m;
ll k,ans;
ordered_set<ll> T;
int main()
{
    n=rd();
    for(int i=1;i<=n;i++)
    {
        int op=rd();k=rd<ll>();
        if(op==1) T.insert((k<<20)+i);
        if(op==2) T.erase(T.lower_bound(k<<20));
        if(op==3) printf("%d\n",T.order_of_key((k<<20))+1);
        if(op == 4)ans=*T.find_by_order(k-1),printf("%lld\n",ans>>20);
        if(op == 5)ans=*--T.lower_bound(k<<20),printf("%lld\n",ans>>20);
        if(op == 6)ans=*T.upper_bound((k<<20)+n),printf("%lld\n",ans>>20);
    }
    return 0;
}
splay_tree_tag

Code from

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <ext/pb_ds/assoc_container.hpp> 
using namespace std;
using namespace __gnu_pbds;
#define Node pair<int,int>
map <int,int> s;
tree< Node ,null_type,less< Node >,splay_tree_tag,tree_order_statistics_node_update> T;
int n,op,x;
int main()
{
    scanf("%d",&n);
    for(register int i = 1; i <= n; i++)
        switch(scanf("%d%d",&op,&x), op)
        {
            case 1 :T.insert(Node(x,s[x]++));
                    break;
            case 2 :T.erase(Node(x,--s[x]));
                    break;
            case 3 :printf("%d\n",(int)T.order_of_key(Node(x,0))+1);
                    break;
            case 4 :printf("%d\n",T.find_by_order(x-1)->first);
                    break;
            case 5 :printf("%d\n",T.find_by_order(
                    T.order_of_key(Node(x,0))-1
                                                      )->first);
                    break;
            case 6 :printf("%d\n",T.find_by_order(
                    T.order_of_key(Node(x,s[x]-1))+(T.find(Node(x,0)) == T.end() ? 0 : 1)
                                                      )->first);
                    break;
            default:break;
        }
    return 0;
}

底层代码


参考以及进阶

比STL还STL?——平板电视
pb_ds库的一些常用方法
C++ __gnu_pbds(平板电视)超详细教程(C++内置的平衡树,字典树,hash)

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值