我正在构建一个使用std::map<tuple<...>>
作为查找数据结构的类。我希望能够在地图上进行前缀搜索,以查找在元组内共享特定前缀的所有元素。例如:
using namespace std;
map<tuple<int,int,int,string>,Value> index;
index.insert(make_tuple(1,1,1,"a"),Value());
index.insert(make_tuple(1,1,2,"b"),Value());
index.lower_bound(make_tuple(1,1,std::numeric_limits<int>::min(),""));
这正是我需要的但我必须手动(对于非POD类型)找出最小值。更糟糕的是,当我想找到具有特定前缀的最高元素时(我这样做),我必须找到某个类型的最大元素值,在string
的情况下,这是相当有问题的。
理想情况下,我可以提供map.find/lower_bound/upper_bound
(不是std :: find,这是地图上的线性复杂性),并且单独比较不考虑后缀,但不幸的是,这是不可能的,很可能因为前缀搜索或多或少是唯一明智的应用程序。
我认为选项会修改map在运行时使用的比较(我认为风格非常糟糕)或者为元组内部的所有类型实现numeric_limits等价物。
在地图/集上进行前缀搜索是否有更好的选择?
答案 0 :(得分:2)
在定义时,您可以将“静态”比较仿函数传递给map
。 tuple<...>
上的默认排序是类型的词典排序。
将密钥类型扩展为允许将字段标记为max
或min
值的密钥类型,并提供接受它们的排序算法。
即,像这样:
template<typename T>
struct InfiniteExtensionOf
{
enum ExtendedOrder {NegInfinity=-1, Normal=0, PosInfinity=1};
ExtendedOrder order;
T value;
bool operator<(InfiniteExtensionOf const& other) const
{
if (order != other.order)
return order<other.order;
return value < other.value;
}
template<typename U>
InfiniteExtensionOf( U&& u ):order(Normal),value(std::forward(u)) {}
InfiniteExtensionOf( InfiniteExtensionOf&& other ):order(other.order),value(std::move(other.value)) {}
InfiniteExtensionOf( InfiniteExtensionOf& other ):order(other.order),value(other.value) {}
InfiniteExtensionOf( InfiniteExtensionOf const& other ):order(other.order),value(other.value) {}
InfiniteExtensionOf( ExtendedOrder& eo ):order(eo), value() {}
InfiniteExtensionOf( ExtendedOrder&& eo ):order(eo), value() {}
InfiniteExtensionOf( ExtendedOrder const& eo ):order(eo), value() {}
};
然后像这样关键:
map<tuple<InfiniteExtensionOf<int>, InfiniteExtensionOf<int>, InfiniteExtensionOf<int>, InfiniteExtensionOf<string>>, Value> myMap;
哪个接受tuple
s而没有InfiniteExtensionOf
参数(因为这样的元组隐式转换,我希望),你可以在调用时轻松指定+ inf或-inf作为特定字段的值lower_bound
或upper_bound
。
...
请注意,如果lower_bound
采用了模板参数,并且只要求它以与现有顺序一致的方式与地图中的元素兼容,那么这将不那么麻烦。 :)但遗憾的是,事实并非如此。
答案 1 :(得分:1)
你可以做的是不直接使用密钥类型,而是选择类型的三态版本:
small
标志,则认为该值小于所有其他值。large
标志,则认为该值大于任何其他值。要查找下限,您可以搜索,例如使用small
值:
map.lower_bound(srd::make_tuple(
tristate<int>(17),
tristate<std::string>(tristate_small)));
这是针对具有由int
和std::string
组成的密钥的地图,每个密钥可能被小值或大值替换。