C++STL之雜湊表
C++ STL中,雜湊表對應的容器是unordered_map
(since C++ 11)。根據 C++ 11 標準的推薦,用unordered_map
代替hash_map
。
雜湊表
先來回顧一下資料結構中雜湊表相關的知識。
雜湊表是根據關鍵碼值(key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度,這個對映函式叫做雜湊函式。
雜湊表的一個重要問題就是如何解決對映衝突的問題。常用的有兩種:開放地址法和鏈地址法。
STL中,map
對應的資料結構是紅黑樹。紅黑樹是一種近似於平衡的二叉查詢樹,裡面的資料是有序的。在紅黑樹上做查詢操作的時間複雜度為O(logN)
unordered_map
對應雜湊表,雜湊表的特點就是查詢效率高,時間複雜度為常數級別O(1), 而額外空間複雜度則要高出許多。所以對於需要高效率查詢的情況,使用unordered_map
容器。而如果對記憶體大小比較敏感或者資料儲存要求有序的話,則可以用map
容器。
說明
-
unordered_map 是一種關聯容器,用於儲存由關鍵值 (Key Value,以下稱為Key 值) 和對映值 (Mapped Value,以下稱為對映值) 組成的元素,並且允許根據其 Key 值快速檢索各個元素。
-
在 unordered_map 容器中,Key 值通常用來唯一標識元素,對映值是與該 Key 值關聯內容的物件。Key 值與對映值的型別可能不同。
-
在 unordered_map 內部,元素沒有按照其 Key 值與對映值的任何順序進行排序 ,而是根據它們的 Hash 值組織成桶,允許它們通過其 Key 值直接快速訪問單個元素(通常具有常數等級的平均時間複雜度)。
-
unordered_map 容器與 map 容器相比,通過 Key 值訪問各個元素的速度更快,然而通過其元素子集進行範圍迭代的效率通常較低。
-
unordered_map 實現了直接訪問操作符 (operator[]),它允許使用 Key 值作為輸入引數,直接訪問對映值。
-
容器中的迭代器至少是前向迭代器。
容器屬性
關聯性
關聯容器中的元素的參考地址指的是其 Key 值,而不是他們在容器中的絕對地址;
無序容器使用 Hash 表來組織元素,這些 Hash 表允許無序容器通過 Key 值快速訪問元素;
對映
每個元素將一個 Key 值與對映值關聯起來,Key 值用於標識其主要內容是對映值的元素;
唯一關鍵值
容器中不存在同時擁有相同 Key 值的兩個元素;
分配器感知map 容器使用分配器物件動態處理其儲存需求。
常用函式
bucket
size_type bucket ( const key_type& k ) const;
定位元素所在的桶,返回 Key 值為輸入引數 k 的元素的所在桶號。
桶是容器內部 Hash 表中的一個槽,槽中的元素根據 Key 值分配元素。桶號的編號從 0 到 (bucket_count - 1)。 桶中單個元素可以通過 unordered_map::begin 和 unordered_map::end 返回的範圍迭代器進行訪問。
count
size_type count ( const key_type& k ) const;
搜尋容器中 Key 值為輸入引數 k 的元素,並返回找到元素的數量。由於 unordered_map 容器不允許存在重複的 Key 值,這說明如果容器中存在具有該 Key 值的元素,則該函式返回 1,否則返回 0。
clear
清除 map 中所有元素;
erase
刪除 map 中指定位置的元素;
insert
在 map 指定位置新增 pair 型別的元素;
find
獲取 map 中元素的迭代器;
begin, end
map 的正向迭代器的起始位置與終點位置
例題
摘選自Leetcode 問題 Two Sum:給出一個整數陣列,返回兩個數的下標值,令其和等於一個指定的目標值。
#include <unordered_map>
class Solution {
public:
vector<int> twoSum(vector<int> &numbers, int target)
{
//Key is the number and value is its index in the vector.
unordered_map<int, int> hash;
vector<int> result;
for (int i = 0; i < numbers.size(); i++) {
int numberToFind = target - numbers[i];
//if numberToFind is found in map, return them
if (hash.find(numberToFind) != hash.end()) {
result.push_back(hash[numberToFind]);
result.push_back(i);
return result;
}
//number was not found. Put it in the map.
hash[numbers[i]] = i;
}
return result;
}
};
參考“大專欄”