Set和Unordered_Set的區別


參考文獻:
[1] cppreference中對std::set的介紹:https://zh.cppreference.com/w/cpp/container/set
[2] cppreference中對std::unordered_set的介紹:https://zh.cppreference.com/w/cpp/container/unordered_set
[3] https://blog.csdn.net/haluoluo211/article/details/82468061
[4] https://stackoverflow.com/questions/1349734/why-would-anyone-use-set-instead-of-unordered-set/52203931#52203931

std::set 是關聯容器,含有 Key 類型對象的已排序集。用比較函數 Compare 進行排序。搜索、移除和插入擁有對數復雜度。 set 通常以紅黑樹實現,紅黑樹具有自動排序的功能,因此set內部所有的數據,在任何時候,都是有序的。
std::unordered_set 是含有 Key 類型唯一對象集合的關聯容器,依賴於哈希表。搜索、插入和移除擁有平均常數時間復雜度。在內部,元素並不以任何特別順序排序,而是組織進桶中,元素被放進哪個桶完全依賴其值的哈希。允許對單獨元素的快速訪問,因為一旦哈希,就能夠准確指代元素被放入的桶。不可修改容器元素(即使通過非 const 迭代器),因為修改可能更改元素的哈希,並破壞容器。代價是消耗比較多的內存,無自動排序功能。底層實現上,使用一個下標范圍比較大的數組來存儲元素,形成很多的桶,利用hash函數對key進行映射到不同區域進行保存。

它們的區別見下圖,原文是[3]:

下面幾種情況一般使用set[4]:

  1. 需要有序的數據(元素不同)。
  2. 需要按順序打印/訪問數據。
  3. 需要元素的前任或后繼。

下面幾種情況一般使用unordered_set:

  1. 需要保留一組不同的元素,不需要排序。
  2. 需要訪問單個元素,不要遍歷。

例如:
set:

Input : 1, 8, 2, 5, 3, 9

Output : 1, 2, 3, 5, 8, 9

Unordered_set:

Input : 1, 8, 2, 5, 3, 9

Output : 9 3 1 8 2 5 (這個順序應該是被hash函數影響了)

注意:(在一些情況下set反而比unordered_set更方便),比如使用vector作為鍵值(Key)時。

set<vector<int>> s;
s.insert({1, 2});
s.insert({1, 3});
s.insert({1, 2});

for(const auto& vec:s)
    cout<<vec<<endl;   // I have override << for vector
// 1 2
// 1 3 

因為 vector 重載了小於號 <,所以在 set 中 vector 能作為鍵值存在。
但由於 vector 沒有 hash 函數,想要使用 unordered_set<vector > 需要定義一個,例子如下:

struct VectorHash {
    size_t operator()(const std::vector<int>& v) const {
        std::hash<int> hasher;
        size_t seed = 0;
        for (int i : v) {
            seed ^= hasher(i) + 0x9e3779b9 + (seed<<6) + (seed>>2);
        }
        return seed;
    }
};

vector<vector<int>> two(){
    //unordered_set<vector<int>> s; // error vector<int> doesn't  have hash function
    unordered_set<vector<int>, VectorHash> s;
    s.insert({1, 2});
    s.insert({1, 3});
    s.insert({1, 2});

    for(const auto& vec:s)
        cout<<vec<<endl;
    // 1 2
    // 1 3
}

還有一個需要解決的問題:set中對元素的排序是按照字典順序,那unordered_set中對int/char的hash函數是怎樣實現的?留待之后看一看《STL源碼剖析》


免責聲明!

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



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