从pbds、rope到stl数据结构的奇技淫巧

从pbds、rope到stl数据结构的奇技淫巧

1. pbds
  1. pbds常用的有哈希表,平衡树,以及各种等数据结构。

  2. 首先使用pbds都要加上**using namespace __gnu_pbds;**

  3. 哈希表

    1. #include<ext/pb_ds/assoc_container.hpp>
      #include<ext/pb_ds/hash_policy.hpp>
      
    2. 使用方法

      1. 定义:

        cc_hash_table<int, bool> hash1; //拉链法处理冲突
        gp_hash_table<int, bool> hash2; //探测法处理冲突(较快)
        
      2. 使用

        1. 直接hash1[a]=x,类似map。
        2. 使用hash1.find(a),查找一个键值。
  4. 平衡树

    1. #include <ext/pb_ds/tree_policy.hpp>
      #include <ext/pb_ds/assoc_container.hpp>
      
    2. 使用方法

      1. 定义:

        tree<nod, null_type, less<nod>, rb_tree_tag, tree_order_statistics_node_update> t;//第二维有可能是null_mapped_type(老版本)
        
      2. rb_tree_tag一维可选其他的,但都太慢了。

      3. 会去重!

      4. 迭代器可以–

      5. 使用

        1. .insert(一个元素)
        2. .erase(一个元素)
        3. .order_of_key(一个元素) //求k在树中是第几大
        4. .find_by_order(一个数)//查第几大是谁
        5. .lower_bound() .upper_bound()
        6. .join(另一个树)//要求元素值区间不相交,全大或全小
        7. .split(v,b)key小于等于v的元素属于a,其余的属于b
    3. 高能使用

      1. 自定义类来实现求前缀和之类的操作。

      2. tree_order_statistics_node_update这一维是可以自定义结构体的。

      3. 首先必须的结构是

        template<class Node_CItr,class Node_Itr,class Cmp_Fn,class _alloc> 
        struct my_node_update
        {
        	virtual Node_CItr node_begin() const =0;
        	virtual Node_CItr node_end() const =0;
            typedef int metadata_type;
        };
        
      4. 在这个struct里面要做的就是我们想做的事情啦,添加一些和结点相关的数据,即插入的时候有一个含有数据的第二维,相当于插入的数据是一个结构体。

      5. 首先肯定要定义一个合并左结点和右节点信息的函数,以下为一个例子。

        void operator()(Node_Itr it, Node_CItr end_it)
        {
            Node_Itr l=it.get_l_child();
            Node_Itr r=it.get_r_child();
            int left=0,right=0;
            if(l!=end_it) left=l.get_metadata();
            if(r!=end_it) right=r.get_metadata();
            const_cast<int&> (it.get_metadata())=left+right+(*it)->val;
        }
        
      6. 可以在函数内部自定义一些方法,如下,相当于在平衡树上二分。

        int prefix_sum(int x)
        {
        	int ans=0;
        	Node_CItr it=node_begin();
        	while(it!=node_end())
        	{
        		Node_CItr l=it.get_l_child(),r=it.get_r_child();
        		if(Cmp_Fn()(x,(*it)->first)) it=l;
        		else
        		{
        			ans+=(*it)->second;
        			if(l!=node_end())
        				ans+=l.get_metadata();
        			it=r;
        		}
        	}
        	return ans;
        }
        
      7. 在内部主要使用的函数就是.get_l_child() .get_r_child() .get_metadata()

      8. 自己定义的时候就可以改为 tree<nod, null_type, less<nod>, rb_tree_tag, my_node_update> t;

      9. 太nb了!

    1. #include<ext/pb_ds/priority_queue.hpp>
      
    2. 使用

      1. 定义

        __gnu_pbds ::priority_queue<nod, less<nod>, pairing_heap_tag> a;//要加命名空间防冲突
        
      2. 第一维定义数据类型,第二维greater是大根堆,less是小根堆,第三维选择堆的类型。

      3. 堆的类型的选择

        1. 使用合并的时候使用 pairing_heap_tag
        2. 做dijisktra的时候使用 thin_heap_tag
      4. 用法

        1. .push(一个元素) .pop() .top() .empty() .clear()
        2. .modify(一个迭代器,一个值)
        3. .erase(一个迭代器)
        4. .join(另外一个堆)//最nb的功能!
        5. .split(Pred prd,priority_queue &other)//分成两个堆,在树里可能比较好用
2. rope
  1. 首先要带头文件 #include<ext/rope>
  2. 使用rope还需要带命名空间 using namespace __gnu_cxx;
  3. 定义方法 rope<变量类型>变量名称
  4. 复杂度基本都为 l o g log log级别,据说 1 0 6 10^6 106的字符串只需要不到 1 M B 1MB 1MB的空间!
  5. 用法
    1. 在字符串和整数类型的存储应用较广,在此只讲这两种。
    2. 插入s的前n位:insert(int 起始位置, string &s/int *a, int 长度)
    3. 向末尾插入s的pos开始的n位: append(string &s/int *a,int 串s的起始位置,int 长度)
    4. 取子串:substr(int 起始, int 长度)
    5. 取字符:at(int x)
    6. 删除子串:erase(int 起始, int 长度)
    7. 将rope从pos开始的len个字符用s替代copy(int pos, int len, string &s/int *a)
    8. 将rope从pos开始的字符用s替代 replace(int pos, string &s/int *a);
3. stl
  1. stl奇技淫巧不多,也很常用,不用错就行了。

  2. set

    1. 一个元素只能出现一次
    2. 删除元素之后结构可能发生改变,因此不要边删边跑迭代器。迭代完之后统一删除。
    3. multiset可以出现多个元素
      1. 删除一个值,删除所有等于该值的结点
      2. 要只删除一个值,就删除一个等于该值的指针
  3. map

    1. map nb!
  4. bitset用法整理,转自胡小兔的博客

    foo.size() 返回大小(位数)
    f11oo.count() 返回1的个数
    foo.any() 返回是否有1
    foo.none() 返回是否没有1
    foo.set() 全都变成1
    foo.set(p) 将第p + 1位变成1
    foo.set(p, x) 将第p + 1位变成x
    foo.reset() 全都变成0
    foo.reset(p) 将第p + 1位变成0
    foo.flip() 全都取反
    foo.flip(p) 将第p + 1位取反
    foo.to_ulong() 返回它转换为unsigned long的结果,如果超出范围则报错
    foo.to_ullong() 返回它转换为unsigned long long的结果,如果超出范围则报错
    foo.to_string() 返回它转换为string的结果

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ STL 中的 `tree` 是一个非标准的容器,需要使用第三方库 `GCC-Tree` 才能使用。下面是一个简单的例子,演示如何使用 `tree` 存储一组整数,并对其进行遍历和查找操作: ```c++ #include <iostream> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> using namespace std; using namespace __gnu_pbds; typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set; int main() { ordered_set s; s.insert(10); s.insert(20); s.insert(30); s.insert(40); s.insert(50); cout << "size = " << s.size() << endl; cout << "s[1] = " << *s.find_by_order(1) << endl; cout << "s[2] = " << *s.find_by_order(2) << endl; cout << "s.rank(30) = " << s.order_of_key(30) << endl; cout << "s.rank(40) = " << s.order_of_key(40) << endl; for (auto x : s) { cout << x << " "; } return 0; } ``` 输出结果为: ``` size = 5 s[1] = 20 s[2] = 30 s.rank(30) = 2 s.rank(40) = 3 10 20 30 40 50 ``` 在这个例子中,我们首先定义了一个 `ordered_set` 类型的变量 `s`,它是一个存储整数类型元素的 `tree` 容器。然后,我们向 `s` 中插入了一些元素,使用 `size` 函数查看容器中元素的个数,使用 `find_by_order` 函数查找元素,使用 `order_of_key` 函数查找元素在容器中的排名,最后使用一个 for 循环遍历容器中的元素并输出。 需要注意的是,`tree` 是一个非标准的容器,使用时需要在编译选项中添加 `-std=c++11 -D_GLIBCXX_DEBUG`。此外,`tree` 容器的功能与 `set` 和 `map` 类似,但是由于 `tree` 使用的是红黑树,因此插入和删除操作的时间复杂度要比 `set` 和 `map` 高一些,但是查找操作的时间复杂度相对较低。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值