C ++中的快速地图实现

时间:2011-01-12 13:41:13

标签: c++ map

我现在有一个工作实现,它映射范围的键,如下所示:

class Range {
public:
    Range(int from, int to = -1) : _from(from), _to( to >= 0 ? to : from) {}
    bool operator < (const Range& item) {
        return _to < item._from;
    }
    bool operator == (const Range& item) {
        return item._from >= _from && item._to <= _to;
    }
private:
    int _from, _to;
};

typedef std::map<Range, MappedType> my_map_type;

这件事很酷我可以这样做:

my_map_type m;
m[Range(0, 20)] = Item1;
m[Range(30,40)] = Item2;

my_map_type::iterator it = m.find(15);
assert(it->second == Item1);
it = m.find(40);
assert(it->second == Item2);
it = m_find(25);
assert(it == m.end());

但我需要比 std :: map 更快的地图实现。插入可以很慢,但发现必须非常快。试过 boost :: unordered_map ,但我无法使用 Range 类(虽然我已经为Range对象实现了 boost :: hash_value ) 。 查找不返回任何内容(查找时,运算符== 甚至不会被调用,我觉得很奇怪)

想法?

3 个答案:

答案 0 :(得分:5)

您无法使用哈希表执行此操作,operator==的定义无法与哈希函数兼容:在代码Range(10, 20) == Range(15, -1)中,哈希函数无法返回相同的哈希。

通常,哈希和相等必须兼容:x == y必须暗示hash(x) == hash(y)。当然反过来也不正确。

所以你需要一些基于比较的结构,比如基于树的map。您可以定义一个正确的相等比较器,而不是使用可能会给您带来问题的损坏的operator==,并使用map::lower_bound来完成您正在尝试的操作。

如果它太慢,您可以使用已排序的向量并使用std::lower_bound。搜索时间是O(log n),它与std::map渐近相同,但实际上更快(没有指针追逐,更好的位置)。但是它具有线性更新(插入/删除)时间。

否则你可能想看一下专门的结构,比如interval trees,但它们没有在STL中实现(可能是Boost?)。

无论如何,隐式Range(int)构造函数具有误导性并且可能有害。您应该将其声明为explicit并使用find(Range(40))代替find(40)

答案 1 :(得分:1)

无论是使用std::map还是使用任何其他容器,您尝试执行的操作都无效。您的operator <operator ==与这些运营商的传统要求不符:

  • 如果a == ba == c,那么b == c:在您的情况下,[1,2] == [0,100][98,99] == [0,100],但显然是[1,2] != [98,99]
  • 如果a < b为真,则b < a为假:在您的情况下,[2,4] < [1,3]为真,但[1,3] < [2,4]也为真。

因此,在某些情况下,您的std::map实施也会失败。

不仅如此,std::map只返回一个范围,而可以预期给定的项目可能在地图的多个范围内。

如果您可以安全地假设没有任何范围重叠,那么仅根据from值对范围进行排序,使用upper_bound提取范围小于from的范围您要查找的值,并与该范围的to进行比较,以确定它是否是实际匹配。

答案 2 :(得分:0)

您正在使用std :: map&lt;&gt;通常实现为红黑树。 boost :: multi_index容器还提供基于红黑树的容器,但是带有压缩节点(小于指针的大小),所以它会比std :: map&lt;&gt;更快。由于工作量较小。

另一个选择是使用哈希,这样当你没有哈希冲突时,有些人会查找O(1)。