set/multiset/unordered_set/unordered_multiset关联式容器的基本概念总结

set

set<typename> obj;

set基于RB-Tree实现,RB-Tree具有自动排序的功能,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值;另外,还得保证根节点左子树的高度与右子树高度相等。

multiset

multiset<typename> obj;

multiset和set的唯一区别就是multiset容器允许有重复的元素,插入或删除元素的时间复杂度是O(logn)

unordered_set

unordered_set<typename> obj;

unordered_set基于哈希表实现,是一种无序集合,所以不像基于红黑树的set那样具有排序功能。所以在用迭代器的使用上,set的效率高于unordered_set。

unordered_multiset

unordered_multiset<typename> obj;

基本与unordered_set特点相当,但是允许存在相同的值

set/multiset的特点

  1. 每个元素都是唯一的,也是元素本身,multiset则可以不唯一
  2. 元素的值不能被随意改变
  3. 插入删除搜索效率高,但不如unordered_set,但是占空间小些
  4. 元素在插入时就已经按照一定的方式排序好了

unordered_set/unordered_multiset的特点

  1. unordered_set每个key值都是唯一的,unordered_multiset允许有相同的key值。
  2. 元素的值不能被随意改变
  3. 元素是无序的
  4. 插入删除搜索效率高,但是占空间大些

set/multiset的常用方法

begin() 返回指向容器的第一个元素的迭代器

end() 返回指向容器的最后一个元素的下一个地址迭代器

clear() 删除容器里的所有元素

empty() 判断容器是否为空

max_size() 返回元素可能包含元素最大个数

size() 返回当前容器中元素的个数

rbegin() 相当于end()

rend() 相当于begin()

count() 返回某个值元素的个数(由于set不可以存在重复元素,所以相当于判断是否存在这个元素

find() 返回一个指向被查找到的元素的迭代器

equal_range() 返回集合中与给定值相等的上下限的两个迭代器

erase() 删除集合中的指定元素

insert() 在集合中插入元素

lower_bound() 返回指向大于某值的第一个元素的迭代器

unordered_set/unordered_multiset的常用方法

begin() 返回指向容器的第一个元素的迭代器

end() 返回指向容器的最后一个元素的下一个地址迭代器

cbegin() 相当于end()

cend() 相当于begin()

clear() 删除容器里的所有元素

empty() 判断容器是否为空

max_size() 返回最大存储量

size() 返回当前容器中元素的个数

count() 返回某个值元素的个数(由于set不可以存在重复元素,所以相当于判断是否存在这个元素)

find() 返回一个指向被查找到的元素的迭代器

equal_range() 返回集合中与给定值相等的上下限的两个迭代器

erase() 删除集合中的指定元素

insert()|emplace() 在集合中插入元素

emplace_hint(迭代器,val) 在指定地方插入元素

lower_bound() 返回指向大于某值的第一个元素的迭代器

swap() 交换元素

bucket_count() 哈希表的返回篮子个数

bucket_size(具体篮子) 返回那个篮子的槽大小

示例代码

//set容器的方法具体示例程序,multiset大致是相同的,举一反三吧
int main(int argc, char** argv) {
    set<int> box;
    set<int> box2;
    set<int>::iterator box_start = box.begin();//指向第一个元素的地址,box.rend()指向第一个元素的前一个地址
    set<int>::iterator box_end = box.end(); //指向最后一个元素的下一个地址,box.rbegin()指向最后一个元素
    for (int i = 0; i < 10; i++) {
        box.emplace(i); //插入一个元素  0,1,2,3,4,5,6,7,8,9,
    }
    set<int>::iterator it1 = box.emplace_hint(box_start,10); //在特定地方插入一个元素(set是基于红黑树自动排序的,所以只是插入一个元素) 0,1,2,3,4,5,6,7,8,9,10
    /***enplace_hint对比其他插入方法有些不同的就是返回值类型是一个迭代器,插入成功返回该迭代器,插入失败返回与插入值相同的已经存在的值的迭代器地址。***/
    box.insert(11); //也是插入一个元素 0,1,2,3,4,5,6,7,8,9,10,11
    pair<set<int>::iterator,bool> it2 = box.insert(9); //因为set的特性不能存在相同元素,所以插入失败 0,1,2,3,4,5,6,7,8,9,10,11
    /***insert,emplace返回值都是pair对象,包括一个迭代器和布尔变量。插入成功返回迭代器地址和true,插入失败返回.end()和false。***/
    box.swap(box2); //box的元素和box2的元素交换,因为box2是空的,所以box空了,box2得到了box的所有元素
    box.empty(); //返回true
    box2.swap(box);
    box.empty(); //返回false
    auto a = box.count(11); //返回1则存在11这个元素
    box.erase(11); //删除11这个元素 0,1,2,3,4,5,6,7,8,9,10
    auto b = box.count(11); //返回0这个元素不存在
    pair<set<int>::iterator, set<int>::iterator> it3 = box.equal_range(3); //it3->first = 3 ,it3->second = 4
    auto it4 = box.find(5); //查找这个元素,返回值是这个元素的迭代器,找不到就返回end()
    int maxsize = box.max_size(); //maxsize = 214748364 返回容器最大能存储多少个元素
    int size = box.size(); //size = 11 返回当前容器有多少个元素
    auto it5 = box.lower_bound(5); //返回第一个大于等于val的迭代器,这里就是返回5的迭代器咯
    box.clear(); //清空整个容器
    return 0;
}

总结

set和unordered_set每个节点都只能存放一个元素,元素都不能相同。但是由于底层实现原理不同。所以查找、插入、删除,用unordered_set。需要迭代遍历就用set。multiset和unordered_multiset则是可以允许元素相同的,可以按照这4种容器各自的特点灵活使用解决问题。

参考资料

www.cplusplus.com

posted @ 2020-09-02 08:27  JoyooO  阅读(326)  评论(0编辑  收藏  举报