1. 程式人生 > 其它 >C++STL之雜湊表

C++STL之雜湊表

技術標籤:C++c++stlHash雜湊

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;
    }
};

參考“大專欄”