unordered_map

轉載自https://www.sczyh30.com/posts/C-C/cpp-stl-hashmap/
C++ STL中,哈希表對應的容器是unordered_map(since C++ 11)。根據 C++ 11 標準的推薦,用 unordered_map 代替 hash_map

Prologue
先來回顧一下數據結構中哈希表相關的知識。

哈希表是根據關鍵碼值(key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度,這個映射函數叫做散列函數。

哈希表的一個重要問題就是如何解決映射衝突的問題。常用的有兩種:開放地址法鏈地址法


map 的區別
STL中,map 對應的數據結構是 紅黑樹。紅黑樹是一種近似於平衡的二叉查找樹,裏面的數據是有序的。在紅黑樹上做查找操作的時間複雜度爲 O(logN)。而 unordered_map 對應 哈希表,哈希表的特點就是查找效率高,時間複雜度爲常數級別 O(1), 而額外空間複雜度則要高出許多。所以對於需要高效率查詢的情況,使用 unordered_map 容器。而如果對內存大小比較敏感或者數據存儲要求有序的話,則可以用 map 容器。


基本使用
unordered_map 的用法和 map 大同小異,一個簡單示例:

#include <iostream>
#include <unordered_map>
#include <string>
int main(int argc, char **argv) {
    std::unordered_map<int, std::string> map;
    map.insert(std::make_pair(1, "Scala"));
    map.insert(std::make_pair(2, "Haskell"));
    map.insert(std::make_pair(3, "C++"));
    map.insert(std::make_pair(6, "Java"));
    map.insert(std::make_pair(14, "Erlang"));
    std::unordered_map<int, std::string>::iterator it;
    if ((it = map.find(6)) != map.end()) {
        std::cout << it->second << std::endl;
    }
    return 0;
}

使用自定義類
要使用哈希表,必須要有對應的計算散列值的算法以及判斷兩個值(或對象)是否相等的方法。
在 Java 中,Object 類裏有兩個重要方法:hashCode 和 equals 方法。其中 hashCode 方法便是爲散列存儲結構服務的,用來計算散列值;而 equals 方法則是用來判斷兩對象是否等價。由於所有的類都繼承自 java.lang.Object 類,因此所有類相當於都擁有了這兩個方法。

而在 C++ 中沒有自動聲明這類函數,STL 只爲 C++ 常用類提供了散列函數,因此如果想在 unordered_map 中使用自定義的類,則必須爲此類提供一個哈希函數和一個判斷對象是否相等的函數(e.g. 重載 == 運算符)。下面是一個簡單示例(扒自數據結構上機作業的部分代碼):

using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::unordered_map;
class Person {
public:
    string phone;
    string name;
    string address;
    explicit Person() {}
    explicit Person(string name, string phone, string address): name(name), phone(phone), address(address) {}
    // overload operator==
    bool operator==(const Person& p) {
        return this->phone == p.phone && this->name == p.name
            && this->address == p.address;
    }
    inline friend std::ostream& operator<<(std::ostream& os, Person& p) {
        os << "[Person] -> (" << p.name << ", " << p.phone << ", "
           << p.address << ")";
        return os;
    }
};
// declare hash<Person>
namespace std {
 template <>
 struct hash<Person> {
     std::size_t operator()(const Person& p) const {
      using std::size_t;
      using std::hash;
      using std::string;
      // Compute individual hash values for first,
      // second and third and combine them using XOR
      // and bit shifting:
      return ((hash<string>()(p.phone)
        ^ (hash<string>()(p.name) << 1)) >> 1)
        ^ (hash<string>()(p.address) << 1);
     }
 };
}
unordered_map<string, Person> phoneMap;
void selectByPhone() {
    string phone;
    cout << "Input the phone number: "; cin >> phone;
    unordered_map<string, Person>::iterator it;
    int size = phoneMap.size();
    for(int pc = 0; pc < size; pc++) {
        if((it = phoneMap.find(phone)) != phoneMap.end()) {
            cout << "Query result: " << it->second << endl;
            return;
        }
    }
    cout << "Query result : target_not_found" << endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章