STL的容器分为序列容器和关联容器。它们所表达的数据结构各有不同:
序列容器:vector(变长数组), list(链表), queue(队列), heap(堆算法)等
关联容器:set/mutilset,map/mutilmap,(都表达二叉树,且都由红黑树实现)
关联容器是指容器的元素为键值对(key-value),但这四种关联容器的键值对之间略有差异
一、set/mutilset
set是集合之意,其键值对的键和值相同,那么set更像普通的二叉树即结点是键值和实值。
set的键值不允许相同,所以set的value值也没有相同的。而这也是mutilset和set唯一的不同,mutilset可以有相同的键值。
set是基于红黑树的所以其中的元素会自动排序。
set常用操作:
定义set: set<int> a;
插入元素: a.insert(1);
删除元素: a.erase(1);
删除所有元素: a.clear():
判断容器是否为空: a.empty();
返回容器当前元素个数: a.size();
判断元素是否属于集合: if(a.find(1)!=a.end())则属于
集合的并,交,差:
set_union(a.begin(), a.end(), b.begin, b.end(), insert_iterator<set<int> >(c,c.begin()));
set_intersection(a.begin(),a.end(),b.begin(),b.end(),insert_iterator<set<int> >(c,c.begin()));
set_difference(a.begin(),a.end(),b.begin(),b.end(),insert_iterator<set<int> >(c,c.begin()));
以下是收集的关于set的问题:
(1)为何map和set的插入删除效率比用其他序列容器高?
因为对于关联容器来说,不需要做内存拷贝和内存移动。set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。(用节点表示二叉树结构)
因此插入的时候只需要稍做变换,把节点的指针指向新的节点就可以了。删除的时候类似,稍做变换后把指向删除节点的指针指向其他节点也OK了。这里的一切操作就是指针换来换去,和内存移动没有关系。
(2)对set进行增删操作后,迭代器iterator如何变化?
set的迭代器本质上是const_iterator,这是因为RB-tree的结构依赖于数据的组织,如果允许通过iterator改变set元素值,会严重破坏RB-tree结构。
iterator这里就相当于指向节点的指针,内存没有变,指针就没有失效,只是指向的内容变化了。进行增删操作后,只影响本身的迭代器,对其它迭代器无影响。
示例代码:
1 void test_set() 2 { 3 set<int> a; 4 for (int i=2;i<9;i++) 5 { 6 a.insert(i); 7 } 8 a.insert(1); 9 cout<<"set中第一个元素:"<<*a.begin()<<endl; 10 cout<<"set中元素个数:"<<a.size()<<endl; 11 int arr[]={9,10,11}; 12 a.insert(arr,arr+2); 13 set<int>::iterator iter; 14 for (iter=a.begin();iter!=a.end();iter++) 15 { 16 cout<<*iter<<" "; 17 } 18 cout<<endl; 19 a.erase(1); 20 set<int>::iterator itl=a.begin(); 21 itl++; 22 itl++; 23 a.erase(a.begin(),itl); 24 for (iter=a.begin();iter!=a.end();iter++) 25 { 26 cout<<*iter<<" "; 27 } 28 return; 29 }