【发布时间】:2019-01-13 16:14:11
【问题描述】:
我经常需要一个容器,其中哈希与任意对象相关联(如果两个不同的对象具有相同的哈希,理论上可能发生冲突)。
在 C++98 中,我将使用 template<class Key, class T> class std::map 使用 Key 作为在 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);
}
但是从 C++11 开始,我们已经对容器进行了哈希处理,所以我预计会是这样的:
template<class T, class Key = std::hash<T>> class std::hashed_map
要求为T 类型提供自定义std::hash,但我们有
template<class Key, class T, class Hash = std::hash<Key>> class unordered_map
这不适用于我的关键是哈希本身的场景,并且没有与任意对象相关的其他“关键”概念。
和我预期的差不多:
template<class Key, class Hash = std::hash<Key>> class unordered_set
但没有基于哈希的查找函数。
在现代 C++ 中是否有一个使用哈希的内置容器并具有基于这些哈希的查找接口?
【问题讨论】:
-
我认为您需要查看 wikipedia 以了解哈希映射是什么。你在 C++03 中所做的在很多层面上都是错误的。
-
任何散列容器都需要一个真正的密钥来消除散列冲突,因为散列(通常)是有损的。因此,您既需要真实密钥又需要哈希的情况正是哈希用于可能产生冲突的快速查找的正常用例。为什么你想自己生成哈希而不是让容器调用对你来说可能是相同的哈希?
-
所以也许我误用了“散列映射”这个术语,但这里的需求非常明确:将任意对象与散列相关联。该对象没有额外的“密钥”。这有点像 git,每个提交都有自己的哈希值,是的,理论上冲突是可能的。
-
好吧,忽略碰撞的可能性在某些情况下可能是愚蠢的,但在其他情况下是可以接受的。然而,C++ 容器并不能那样工作,即使在哈希冲突的情况下,它们也能提供 100% 的可靠性。为什么要妥协?
-
@UlrichEckhardt 关键是在这种情况下,除了哈希之外,我没有任何其他密钥。 Git 使用 SHA-1 并忽略碰撞,因为它们在统计上不太可能发生(除非是故意的碰撞攻击)。
标签: c++ hashmap containers