簡體   English   中英

std :: unordered_map的哈希值

[英]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,而輸入的空間大得多。 但是,這並不重要,因為根據輸入的性質,你不能有一個單射散列函數。 一個好的哈希函數具有以下特性:

  • 它不容易顛倒。 給定輸出k,在宇宙的生命周期內找到m使得h(m)= k在計算上是不可行的。
  • 范圍均勻分布在輸出空間上。
  • 很難找到兩個輸入m和m',使得h(m)= h(m')

當然,這些的范圍實際上取決於您是否想要一些加密安全的東西,或者您想要獲取一些任意數據塊並且只是發送一些任意的64位整數。 如果你想要一些加密安全的東西,自己編寫它並不是一個好主意。 在這種情況下,您還需要保證函數對輸入中的微小變化敏感。 std::hash函數對象不需要加密安全。 它存在用於哈希表同構的用例。 CPP Rerefence說:

對於不相等的兩個不同參數k1k2std::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說:

對於兩個相等的參數k1k2std::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM