[关闭]
@lychee123 2017-08-17T10:30:48.000000Z 字数 2524 阅读 2234

pb_ds之红黑树

STL


在GNU C++的pb_ds库中,有可以调用的红黑数模板,可用于实现set的全部功能,并且还可以快速的求数的排名,和第k小等。

需要包含的头文件和命名空间

  1. #include<bits/stdc++.h>
  2. #include<ext/pb_ds/assoc_container.hpp>
  3. using namespace std;
  4. using namespace __gnu_pbds;

定义一颗红黑树

  1. tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> t;

第一个参数代表key的类型
第二个参数表示value的类型。这里不需要映射值,也就填null_type。在老版本G++中这个需要替换为null_mapped_type(如BZOJ)。
第三个参数表示key的排序方式,从小到大。
第四个参数表示使用哪种数据结构,rb_tree_tag表示红黑树。
第五个参数表示如何更新保存节点信息,填写tree_order_statistics_node_update会额外获得order_of_key()和find_by_order()两个功能。

tree也使用和set类似的迭代器,定义为

  1. tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update>::iterator it;

要保证迭代器类型要和定义的树的类型相同。但是为了方便,在条件允许的情况下,可以用auto来自动推断类型。如:

  1. auto it = t.begin();

当然这个迭代器支持++和--操作。
功能简介

1、tree包含set的全部功能,如lower_bound, upper_bound, insert, erase, find, begin, end, rbegin等。
2、查询第k+1小的数,使用find_by_order()函数,返回的为迭代器。

  1. cout << *t.find_by_order(2) << endl;

此时输出的为排名为3的数,注意,查询的是为第k+1小的数。如果传入的k值非法,则会返回end()。
3、查询比x小的数的个数,注意,是比x小的个数,不是x的排名!查询的出的值是排名-1。

  1. cout << t1.order_of_key(2) << endl;

4、合并两个类型相同的tree,t1.join(t2)。t2的内容会全部加入到t1,t2被清空。要保证t1的值全部小于t2或者全部大于t2,否则会抛出异常。
5、不支持多重值,如果需要多重值,可以再开一个unordered_map来记录值出现的次数。将x<<32后加上出现的次数后插入tree。注意此时应该为long long类型。

  1. auto it=t.begin();
  2. it--;
  3. //此时的
  4. it==t.end();
  5. t.end()不是最后一位,是最后一位的下一位

例子:PowerOJ2268
代码

  1. #include<bits/stdc++.h>
  2. #include<ext/pb_ds/assoc_container.hpp>
  3. using namespace std;
  4. using namespace __gnu_pbds;
  5. int main()
  6. {
  7. tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> t;
  8. char s[20];
  9. while(~scanf("%s", s), s[0] != '-')
  10. {
  11. if(s[0] == 'i')
  12. {
  13. int x;
  14. scanf("%d", &x);
  15. t.insert(x); //插入x值
  16. }
  17. else if(s[0] == 'd')
  18. {
  19. int x;
  20. scanf("%d", &x);
  21. auto it = t.find(x); //查询x值
  22. if(it != t.end()) t.erase(x); //删除x值,也可以删除迭代器
  23. else printf("Input Error\n");
  24. }
  25. else if(s[0] == 'p')
  26. {
  27. if(s[2] == 'e')
  28. {
  29. int x;
  30. scanf("%d", &x);
  31. auto it = t.find(x);
  32. if(it != t.end())
  33. {
  34. it--; //迭代器--,求前驱
  35. if(it == t.end()) printf("%d is the minimum\n", x);
  36. else printf("The predecessor of %d is %d\n", x, *it);
  37. }
  38. else printf("Input Error\n");
  39. }
  40. else
  41. {
  42. for(auto &i : t) printf("%d,", i); //遍历整个树,用迭代器遍历从beign到end也可以
  43. printf("end of print\n");
  44. }
  45. }
  46. else if(s[0] == 's')
  47. {
  48. int x;
  49. scanf("%d", &x);
  50. auto it = t.find(x);
  51. if(it != t.end())
  52. {
  53. it++; //迭代器++,求前驱
  54. if(it == t.end()) printf("%d is the maximum\n", x);
  55. else printf("The successor of %d is %d\n", x, *it);
  56. }
  57. else printf("Input Error\n");
  58. }
  59. else if(s[0] == 'K')
  60. {
  61. int x;
  62. scanf("%d", &x);
  63. if(x > t.size() || x <= 0) printf("Input Error\n");
  64. else printf("The %d_th element is %d\n", x, *t.find_by_order(x - 1)); //查第k小,注意-1
  65. }
  66. else if(s[0] == 'r')
  67. {
  68. int x;
  69. scanf("%d", &x);
  70. auto it = t.find(x);
  71. if(it != t.end()) printf("The rank of %d is %d_th\n", x, t.order_of_key(x) + 1); //查排名,注意+1
  72. else printf("Input Error\n");
  73. }
  74. else
  75. {
  76. printf("end of this test\n");
  77. t.clear(); //清空
  78. }
  79. }
  80. return 0;
  81. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注