C++ std::无序_映射中的键与散列

C++ std::无序_映射中的键与散列,c++,hashmap,containers,C++,Hashmap,Containers,我经常需要一个容器,其中散列与任意对象关联(如果两个不同的对象具有相同的散列,则理论上可能发生冲突) 在C++98中,我将使用模板类std::map使用键作为在T上计算的哈希: struct object; typedef std::string object_hash; object_hash compute_hash(const object& obj); std::map<object_hash, object> hash_map; object_hash ins

我经常需要一个容器,其中散列与任意对象关联(如果两个不同的对象具有相同的散列,则理论上可能发生冲突)

在C++98中,我将使用
模板类std::map
使用
作为在
T
上计算的哈希:

struct object;
typedef std::string object_hash;

object_hash compute_hash(const object& obj);

std::map<object_hash, object> hash_map;

object_hash insert_or_assign(const object& obj)
{
    object_hash hash = compute_hash(obj);
    hash_map[hash] = obj;
    return hash;
}

std::pair<bool, object> get_at(const object_hash& hash)
{
    std::map<object_hash, object>::iterator iter = hash_map.find(hash);
    if( iter == hash_map.end() )
        return std::pair<bool, object>(false, object());
    else
        return std::pair<bool, object>(true, iter->second);
}
这不适用于我的场景,其中键是散列本身,并且没有其他与任意对象相关的“键”概念

与我的预期类似的是:

template<class Key, class Hash = std::hash<Key>> class unordered_set
模板类无序集
但是没有基于散列的查找函数


<>在现代C++中有一个内置的容器,它使用散列并基于这些散列有一个查找接口?< /p> < p>您有一个映射而不是哈希映射;密钥是散列的事实与容器无关

唯一显著的特点是你很少关心散列的顺序;所以无序的地图可能是最好的


使用旧的解决方案,将map替换为无序map,将
less
操作替换为
equal
,并将哈希(可能向下)替换为64位。例如,经典的指针散列只是
重新解释cast(key)

你有一个映射而不是散列映射;密钥是散列的事实与容器无关

唯一显著的特点是你很少关心散列的顺序;所以无序的地图可能是最好的


使用旧的解决方案,将map替换为无序map,将
less
操作替换为
equal
,并将哈希(可能向下)替换为64位。例如,经典的指针散列只是代码> RealTytCase:Key(<)>代码> .< /P> < P>最初的<代码>无序的映射> /CODE >被称为代码> Hash映射-< /COD>,然后ISO C++委员会明智地将它重命名为因为
std::map
std::unordered_map
之间的重要区别是不是第一个使用二叉树,而后者使用散列,但是第一个是有序的,而后者保证恒定的时间复杂度

因此,
std::unordered_map
在内部使用散列的事实只不过是一个实现细节:如果键是自定义类型(并且键不经常是自定义类型),则只需要提供一个
std::hash
专门化。除此之外,您应该忘记这个容器的内部哈希


尽管有一些评论,如果您的密钥是散列,那么您的C++98实现绝对没有问题。你可以在C++中使用它,在可能的情况下将它更新并整理到新的语言设施。

< P>最初的<代码>无序的地图> /代码>被称为代码> HasyMaP,然后ISO C++委员会明智地将它重命名为“11”。因为
std::map
std::unordered_map
之间的重要区别是不是第一个使用二叉树,而后者使用散列,但是第一个是有序的,而后者保证恒定的时间复杂度

因此,
std::unordered_map
在内部使用散列的事实只不过是一个实现细节:如果键是自定义类型(并且键不经常是自定义类型),则只需要提供一个
std::hash
专门化。除此之外,您应该忘记这个容器的内部哈希


尽管有一些评论,如果您的密钥是散列,那么您的C++98实现绝对没有问题。在C++中,你可以继续使用它,在可能的情况下将它更新并整理到新的语言设施。

我想你需要看看维基百科,看看哈希地图是什么。你在C++03中所做的在很多方面都是错误的。任何散列容器都需要一个真正的键来消除散列冲突的歧义,因为散列(通常)是有损的。因此,您同时需要一个实键和一个散列的情况,正是散列用于可能产生冲突的快速查找的正常使用情况。为什么你想自己生成散列,而不是让容器调用你认为是同一个散列器呢?所以也许我误用了术语“散列映射”,但这里的需要非常清楚:将任意对象与散列关联起来。该对象没有其他“键”。它类似于git,每个提交都有它的散列,是的,理论上冲突是可能的。忽略冲突的可能性在某些情况下可能是愚蠢的,或者在其他情况下是可以接受的。然而,C++容器不这样工作,即使在哈希冲突的情况下,它们也提供100%的可靠性。为什么要妥协?@UlrichEckhardt问题是,在这个场景中,除了散列,我没有任何其他密钥。Git使用SHA-1并忽略冲突,因为它们在统计上不太可能发生(除非是故意的冲突攻击)。我认为您需要在wikipedia上了解什么是哈希映射。你在C++03中所做的在很多方面都是错误的。任何散列容器都需要一个真正的键来消除散列冲突的歧义,因为散列(通常)是有损的。因此,您同时需要一个实键和一个散列的情况,正是散列用于可能产生冲突的快速查找的正常使用情况。为什么你想自己生成散列,而不是让容器调用你认为是同一个散列器呢?所以也许我误用了术语“散列映射”,但这里的需要非常清楚:将任意对象与散列关联起来。该对象没有其他“键”。它类似于git,每个提交都有它的散列,是的,理论上冲突是可能的。忽略冲突的可能性在某些情况下可能是愚蠢的,或者在其他情况下是可以接受的。然而,C++容器不这样工作,即使在哈希冲突的情况下,它们也提供100%的可靠性。为什么要妥协?@UlrichEckhardt关键是我没有其他的钥匙
template<class Key, class T, class Hash = std::hash<Key>> class unordered_map
template<class Key, class Hash = std::hash<Key>> class unordered_set