[英]Hash value for a std::unordered_map
根據標准, std::hash
類中不支持容器(更不用說無序容器)了。 所以我想知道如何實現這一點。 我有的是:
std::unordered_map<std::wstring, std::wstring> _properties;
std::wstring _class;
我想過迭代條目,計算鍵和值的各個哈希值(通過std::hash<std::wstring>
)並以某種方式連接結果。
如果沒有定義地圖中的順序,那么這樣做的好方法是什么?
注意:我不想使用boost。
提出了一個簡單的異或,所以它會是這樣的:
size_t MyClass::GetHashCode()
{
std::hash<std::wstring> stringHash;
size_t mapHash = 0;
for (auto property : _properties)
mapHash ^= stringHash(property.first) ^ stringHash(property.second);
return ((_class.empty() ? 0 : stringHash(_class)) * 397) ^ mapHash;
}
?
我真的不確定這個簡單的XOR是否足夠。
如果足夠,你的意思是你的函數是否是單射的,答案是否定的。推理是你的函數可以輸出的所有散列值的集合的基數為2 ^ 64,而輸入的空間要大得多。 但是,這並不重要,因為根據輸入的性質,你不能有一個單射散列函數。 一個好的哈希函數具有以下特性:
當然,這些的范圍實際上取決於您是否想要一些加密安全的東西,或者您想要獲取一些任意數據塊並且只是發送一些任意的64位整數。 如果你想要一些加密安全的東西,自己編寫它並不是一個好主意。 在這種情況下,您還需要保證函數對輸入中的微小變化敏感。 std::hash
函數對象不需要加密安全。 它存在用於哈希表同構的用例。 CPP Rerefence說:
對於不相等的兩個不同參數
k1
和k2
,std::hash<Key>()(k1) == std::hash<Key>()(k2)
的概率應該非常小,接近1.0/std::numeric_limits<size_t>::max()
。
我將在下面說明您當前的解決方案並不能真正保證這一點。
我會給你一些關於你的解決方案變體的觀察(我不知道你的_class
成員是什么)。
std::size_t hash_code(const std::unordered_map<std::string, std::string>& m) {
std::hash<std::string> h;
std::size_t result = 0;
for (auto&& p : m) {
result ^= h(p.first) ^ h(p.second);
}
return result;
}
生成碰撞很容易。 請考慮以下地圖:
std::unordered_map<std::string, std::string> container0;
std::unordered_map<std::string, std::string> container1;
container0["123"] = "456";
container1["456"] = "123";
std::cout << hash_code(container0) << '\n';
std::cout << hash_code(container1) << '\n';
在我的機器上,使用g ++ 4.9.1進行編譯,輸出:
1225586629984767119
1225586629984767119
關於這是否重要的問題出現了。 與此相關的是,您有多少時間可以獲得鍵和值相反的地圖。 這些碰撞將發生在任何兩個映射之間,其中鍵和值集是相同的。
具有完全相同鍵值對的兩個unordered_map
實例不一定具有相同的迭代次序。 CPP Rerefence說:
對於兩個相等的參數
k1
和k2
,std::hash<Key>()(k1) == std::hash<Key>()(k2)
。
這是哈希函數的一個簡單要求。 您的解決方案避免了這種情況,因為迭代的順序無關緊要,因為XOR是可交換的。
如果您不需要加密安全的東西,您可以稍微修改您的解決方案以消除對稱性。 對於散列表等,這種方法在實踐中是可行的。 此解決方案還獨立於unordered_map
中的unordered_map
未定義的事實。 它使用您的解決方案使用的相同屬性(XOR的交換)。
std::size_t hash_code(const std::unordered_map<std::string, std::string>& m) {
const std::size_t prime = 19937;
std::hash<std::string> h;
std::size_t result = 0;
for (auto&& p : m) {
result ^= prime*h(p.first) + h(p.second);
}
return result;
}
在這種情況下,哈希函數中所需要的只是將鍵值對映射到任意良好哈希值的方法,以及使用可交換操作組合鍵值對的哈希的方法。 這樣,順序無關緊要。 在我寫的示例hash_code
,鍵值對散列值只是鍵的散列和值的散列的線性組合。 你可以構造一些更復雜的東西,但沒有必要。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.