【C++】关联式容器(set)详解

关联式容器

  关联容器与序列容器有着根本性的不同,序列容器的元素是按照在容器中的位置来顺序保存和访问的,而关联容器的元素是按关键元素来保存和访问的。关联容器支持高效的关键字查找与访问。两个主要的关联容器类型是map与set。

set

  1. 概念:
    set里面每个元素只存有一个key,它支持高效的关键字查询操作。set对应数学中的“集合”。

  2. 特性

    • 储存同一类型的数据元素(这点和vector、queue等其他容器相同)
    • 每个元素的值都唯一(没有重复的元素)
    • 根据元素的值自动排列大小(有序性)
    • 无法直接修改元素
    • 高效的插入删除操作
  3. 声明
    set< T > a;

  4. 常用函数
    在这里插入图片描述

  5. 插入元素:

  • a.insert(x) :其中a为set型容器,x为T型变量
	set<int> a={
    
    0,1,2,9};
	a.insert(6);
	for(auto it = a.begin();it != a.end();it++)	cout << *it;//输出01269
  • a.insert(first,second):其中first为指向区间左侧的迭代器,second为指向右侧的迭代器。作用是将first到second区间内元素插入到a(左闭右开)。
set<int> a = {
    
    0,1,2,9};
set<int> b = {
    
    3,4,5};
auto first = b.begin();
auto second = b.end();
a.insert(first,second);
for(auto it = a.begin();it != a.end();it++)	cout << *it;//0123459

插入元素会自动插入到合适的位置,使整个集合有序

  • 删除元素:
  • a.erase(x):删除建值为x的元素
  • a.erase(first,second):删除first到second区间内的元素(左闭右开)
  • a.erase(iterator):删除迭代器指向的元素
  • set中的删除操作是不进行任何的错误检查的,比如定位器的是否合法等- 等,所以用的时候自己一定要注意。
  1. lower_bound 和 upper_bound 迭代器:
  • lower_bound(x1):返回第一个不小于键参数x1的元素的迭代器
  • upper_bound(x2):返回最后一个大于键参数x2的元素的迭代器
  • 由以上俩个函数,可以得到一个目标区间,即包含集合中从’x1’到’x2’的所有元素
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
int main()
{
    
    
	set<int> a = {
    
    0,1,2,5,9};
	auto it2 = a.lower_bound(2);//返回指向第一个大于等于x的元素的迭代器
	auto it = a.upper_bound(2);//返回指向第一个大于x的元素的迭代器
	cout << *it2 << endl;//输出为2
	cout << *it << endl;//输出为5
	return 0;
} 
  1. set的几个问题:
    (1)为何map和set的插入删除效率比用其他序列容器高?

  因为对于关联容器来说,不需要做内存拷贝和内存移动。set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。因此插入的时候只需要稍做变换,把节点的指针指向新的节点就可以了。删除的时候类似,稍做变换后把指向删除节点的指针指向其他节点也OK了。这里的一切操作就是指针换来换去,和内存移动没有关系。

(2)为何每次insert之后,以前保存的iterator不会失效?

  iterator这里就相当于指向节点的指针,内存没有变,指向内存的指针怎么会失效呢(当然被删除的那个元素本身已经失效了)。相对于vector来说,每一次删除和插入,指针都有可能失效,调用push_back在尾部插入也是如此。因为为了保证内部数据的连续存放,iterator指向的那块内存在删除和插入过程中可能已经被其他内存覆盖或者内存已经被释放了。即使时push_back的时候,容器内部空间可能不够,需要一块新的更大的内存,只有把以前的内存释放,申请新的更大的内存,复制已有的数据元素到新的内存,最后把需要插入的元素放到最后,那么以前的内存指针自然就不可用了。特别时在和find等算法在一起使用的时候,牢记这个原则:不要使用过期的iterator。

(3)当数据元素增多时,set的插入和搜索速度变化如何?

  如果你知道log2的关系你应该就彻底了解这个答案。在set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。

猜你喜欢

转载自blog.csdn.net/Vcrossover/article/details/114639198