You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Policy-Based Data Structures实现支持重复的multiset、map并解决模板错误?

如何用__gnu_pbds实现支持重复元素的有序容器(multiset、map等)

嘿,我来帮你搞定这个问题!你之前遇到的编译错误,主要是对__gnu_pbds里tree模板的参数理解不到位,咱们一步步拆解解决:

首先回顾下你已经掌握的:用tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update>可以实现无重复元素的ordered_set。现在要扩展到支持重复元素的multiset,以及处理pair、map、multimap,核心是搞懂tree模板的参数要求。


1. 实现支持重复元素的ordered_multiset

tree的key要求是唯一的,所以要存重复元素,有两种靠谱的方法:

方法一:用pair包装元素(推荐,避免坑)

给每个重复元素绑定一个唯一的递增ID,这样即使值相同,pair整体是唯一的,就能插入多次。代码示例:

#include <iostream>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;

// pair的第一个元素是实际值,第二个是唯一ID保证key唯一
#define ordered_multiset tree<pair<int, int>, null_type, less<pair<int, int>>, rb_tree_tag, tree_order_statistics_node_update>

int main() {
    ordered_multiset oms;
    int unique_id = 0;
    // 插入重复元素
    oms.insert({5, unique_id++});
    oms.insert({1, unique_id++});
    oms.insert({5, unique_id++});
    oms.insert({2, unique_id++});
    
    // 查找第2小的元素(索引从0开始)
    cout << "第2小元素:" << oms.find_by_order(1)->first << endl;
    // 统计小于等于5的元素总数
    cout << "小于等于5的元素数:" << oms.order_of_key({6, 0}) << endl;
    return 0;
}

方法二:使用less_equal<int>

这个方法更直接,但要注意细节:erase(value)会删掉所有匹配的元素,删除单个需要用迭代器;find返回的是任意一个匹配元素。代码示例:

#define ordered_multiset tree<int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update>

int main() {
    ordered_multiset oms;
    oms.insert(5);
    oms.insert(5);
    oms.insert(1);
    
    // 查找第2小的元素
    cout << *oms.find_by_order(1) << endl;
    // 统计小于5的元素个数(order_of_key返回第一个大于目标值的位置)
    cout << oms.order_of_key(5) << endl;
    return 0;
}

2. 实现ordered_map(有序映射)

你之前错误地把map<int,int>作为tree的key,这完全没必要——tree本身就可以直接实现有序映射,只需要把第二个模板参数(Mapped类型)从null_type改成你要的值类型即可。代码示例:

#include <iostream>
#include <string>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;

// 第一个参数是键类型,第二个是值类型
#define ordered_map tree<int, string, less<int>, rb_tree_tag, tree_order_statistics_node_update>

int main() {
    ordered_map om;
    om[1] = "one";
    om[3] = "three";
    om[2] = "two";
    
    // 查找第1个元素(索引从0开始)
    auto it = om.find_by_order(0);
    cout << "第1个元素:" << it->first << " -> " << it->second << endl;
    // 统计键小于3的元素个数
    cout << "键小于3的元素数:" << om.order_of_key(3) << endl;
    return 0;
}

3. 支持pair作为key的ordered_set

你之前的宏定义错误是第三个参数写了less,但less是模板,需要实例化成具体的less<pair<int,int>>。正确的实现:

#include <iostream>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;

// 指定pair的比较器为less<pair<int,int>>
#define ordered_pair_set tree<pair<int, int>, null_type, less<pair<int, int>>, rb_tree_tag, tree_order_statistics_node_update>

int main() {
    ordered_pair_set ops;
    ops.insert({2, 3});
    ops.insert({1, 5});
    ops.insert({2, 1});
    
    // pair的比较规则:先比第一个元素,再比第二个
    auto target = ops.find_by_order(1);
    cout << "第2小的pair:(" << target->first << ", " << target->second << ")" << endl;
    return 0;
}

4. 实现ordered_multimap(支持重复键的有序映射)

类似ordered_multiset,我们把键和唯一ID绑定成pair作为tree的key,值类型是原来的映射值。代码示例:

#include <iostream>
#include <string>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;

// key是pair<键值, 唯一ID>,值是string类型
#define ordered_multimap tree<pair<int, int>, string, less<pair<int, int>>, rb_tree_tag, tree_order_statistics_node_update>

int main() {
    ordered_multimap omm;
    int unique_id = 0;
    omm.insert({{5, unique_id++}, "five"});
    omm.insert({{1, unique_id++}, "one"});
    omm.insert({{5, unique_id++}, "five_duplicate"});
    
    // 查找第2个元素
    auto it = omm.find_by_order(1);
    cout << "第2个元素:" << it->first.first << " -> " << it->second << endl;
    // 统计键小于6的元素总数
    cout << "键小于6的元素数:" << omm.order_of_key({6, 0}) << endl;
    return 0;
}

你之前报错的原因总结

  1. 比较器参数错误:你写的less没有指定模板参数,tree的第三个参数需要的是实例化后的比较器类型(比如less<pair<int,int>>),而不是模板本身。
  2. 映射实现思路错误:想用tree实现map,不需要把map作为key,而是直接利用tree的键值对结构(第一个参数是键,第二个是值)。

内容的提问来源于stack exchange,提问作者Tanny_12

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 00:52:40