std :: map <key_type,value_type =“”> :: find(different_key_type)</key_type,>

时间:2013-05-31 18:16:41

标签: c++ map

我有一张地图:

std::map<TyString, int> myMap;

但是,在某些情况下,我希望通过比较std::map::findTyString == TyStringRef一个条目,即

myMap.find(TyStringRef("MyString"));

原因是TyString包装了一个const char *,它自己分配和解除分配。 但是,对于仅查找条目我不喜欢分配新字符串,而是我只想使用引用(TyStringRef仅包装const char *而不分配或释放内存。)

当然我可以将TyStringRef转换为TyString,但之后我会有上述的内存开销。

有没有一种聪明的方法可以解决这个问题?

谢谢!

2 个答案:

答案 0 :(得分:5)

请注意std::map::find每个默认值使用operator<,或者使用用户定义的比较函数。因此,除非您为operator<TyString重载TyStringRef,否则无法在对数时间内查找密钥。如果operator==超载,您仍然可以在线性时间中查找,但不能使用std::map::find

为此,您应该使用#include <algorithm>中的通用算法,该算法独立于容器类。它可以使用任何类型T,并使用operator==对传入的迭代器的operator*()结果进行比较。

std::find(sequence.begin(), sequence.end(), myKey);

但是,有一个问题:由于你有一个std::map,它使用作为迭代器,键值对将被比较。因此,您必须使用std::find_if,它会使用谓词而不是来搜索。对于您要查找的元素,此谓词应返回true。你想拥有first == myKey的元素(对),所以你得到这样的代码:

std::find_if(myMap.begin(), myMap.end(), [](const std::pair<TyString,int> & pair) {
    return pair.first == TyStringRef("MyString");
};

这在概念上有效,但它不会使用std::map中的二叉树。因此,与std::map::find的对数时间相比,它需要线性时间

有一种替代方案,在开始时看起来有点奇怪,但它的优势在于它将是对数时间查找。 它要求您重载operator<(TyString,TyStringRef)您可以使用std::lower_bound查找第一个元素,该元素不小于(大于或等于)某个元素尊重给定的比较函数。

std::lower_bound(myMap.begin(), myMap.end(), TyStringRef("MyString"),
    [](const std::pair<TyString,int> & entry, const & TyStringRef stringRef) {
        return entry.first < stringRef;
    }
);

在找到“下限”之后,您仍然需要测试密钥是否相等。如果他们不这样做,则找不到该元素。由于所有元素可能与您正在寻找的元素相比较少,因此返回的迭代器可能是结束迭代器,不应该取消引用。所以完整的代码变成了这个,类似于std::map::find,如果找不到密钥则返回结束迭代器:

template<class Map, class KeyCompareType,
         class Iterator = typename Map::const_iterator>
Iterator findInMap(const Map &map, const KeyCompareType &key)
{
    typedef typename Map::value_type value_type;
    auto predicate = [](const value_type & entry, const KeyCompareType & key) {
        return entry.first < key;
    };
    Iterator it = std::lower_bound(map.begin(), map.end(), key, predicate);
    if (it != map.end()) {
        if (!(it->first == key))
            it = map.end();
    }
    return it;
}

Live example

答案 1 :(得分:0)

您可以使用STLport,它已经单独执行此操作。也许其他标准库实现也这样做?或者,您可以使用std :: find(),但这将花费您对数查找。