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源码剖析》

猜你喜欢

转载自www.cnblogs.com/llee-123/p/11265812.html
今日推荐