STL 之 unordered_map


原理

unordered_map 內部實現是散列表,是一個無序的容器。內部實現的散列表采用了鏈地址法,意思是使用鏈表來解決散列沖突。當往容器中加入一個元素的時候,會計算散列值,然后取余之后放到一個桶 (bucket) 里。如果不斷往容器加元素,那么所有的桶都會變成一個很長的鏈表,這樣效率就很低了,這種情況應該如何避免呢?unordered_map 采用了擴容的機制,當負載因子 (load factor) 超過了閾值,就會進行一次擴容。負載因子的計算方法是總鍵值對數除以桶數。擴容的時候,會重新計算散列,重新放入到桶里。

cplusplus 文檔:https://www.cplusplus.com/reference/unordered_map/unordered_map/

代碼聲明

從以下的代碼中,我們可以看到 unordered_map 內部的存儲使用 allocator 來管理的,存儲的是 std::pair 類型的數據。

  template<class _Key, class _Tp,
	   class _Hash = hash<_Key>,
	   class _Pred = std::equal_to<_Key>,
	   class _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
    class unordered_map;

自定義類型

一個自定義的類型,如果要作為 Key,應該如何寫代碼呢?假如我們定義了一個 Apple 類型,里面只有構造器(構造器內部只有輸出)。直接將 Apple 作為 key 會出現報以下錯誤。std::hash<Apple> does not provide a call provider. 這意味着需要我們自定義散列的規則。如果細細思考 unordered_map 的模板參數,你會發現你不僅需要定義散列的規則,還需要定義相等判定的規則。

散列

可以采用的實現方式:

  • 覆寫 operator() 的類或者結構體,需要在 unordered_map 實例化的地方指定模板參數
struct apple_hash {
  std::size_t operator()(const Apple& apple) const {
    return std::hash<int>()(apple.GetData());
  }
};

std::unordered_map<Apple, int, apple_hash> apple_to_int;
  • 特化 std::hash 來實現,經過特化后,在使用 unordered_map 的時候就不用指定模板參數了

特化 std::hash 的方法如下,覆寫 operator() 需要注意幾個細節,返回類型是 size_t,輸入的參數是 const 引用,函數體是 const。

template<>
struct std::hash<Apple> {
  std::size_t operator()(const Apple& apple) const {
    return std::hash<int>()(apple.GetData());
  }
};

判等

  • 覆寫 operator() 的類或者結構體作為模板參數
struct apple_equal {
  bool operator()(const Apple& x, const Apple& y) const {
    std::cout << "apple_equal" << std::endl;
    return x.GetData() == y.GetData();
  }
};

std::unordered_map<Apple, int, std::hash<Apple>, apple_equal> apple_to_int;  // 不知道怎么跳過第三個參數進行實例化hhh
  • 特化 std::equal_to來實現
template<>
struct std::equal_to<Apple> {
  bool operator()(const Apple& x, const Apple& y) const {
    return x.GetData() == y.GetData();
  }
};
  • 覆寫類的 operator==() 方法
bool operator==(const Apple& apple) const {
  return this->data_ == apple.data_;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM