set和map底层都是由红黑树实现的,每个元素都是红黑树的一个个节点;只不过map是key-value模型,每个节点是key—>value(映射)关系;而set是key模型,每个元素只有一个键值(key),同时也是实值(value),同时也不允许有相同的键值,默认按照升序排列,所以set的用法和map差不多。
set的定义:
set<K> s1;
set<K> s2(s1);
int a[] = {1,2,3,4};
set<int> s(a,a+4);
set<int> s3(s.begin(),s.end());
set的常用接口:
1.insert();
与map相似;常用的插入方法:
pair <iterator,bool> insert(const value_type& val);
参数:就是我们要插入的数;
返回值:返回一个pair,pair的第一个元素first是迭代器,第二个元素second是bool值,插入成功,first是指向该元素位置的迭代器,second的值为true;插入失败,说明该元素在set中已经存在,first是该元素位置的迭代器,second的值为false。
例如:
set<int> s;
pair<set<int>::iterator, bool> p;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(4);
p = s.insert(1);
if (p.second == false)
cout << *(p.first) << "已经存在!" << endl;
也可以在指定位置插入:
iterator insert(iterator position,const value_tytpe& val);
与map一样,我们虽然在第一个位置插入8,但是set会自动排序,默认升序。
此时我们应该想到一点,map和set如果频繁的进行插入和删除操作,效率为什么就相对低了;他们的底层是红黑树,每一次的插入和删除都破坏了树的结构欧,为了依然维持结构的有序,都会调整树的结构,所以会影响效率。
2.其他常用的接口与map的用法一样:
就不一个个阐述了,实现一个例子:
int main()
{
set<int> s;
pair<set<int>::iterator, bool> p;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(4);
s.insert(5);
s.insert(6);
//count
int ret = 0;
ret = s.count(1);
if (ret == 1)
cout << "1,该值存在!" << endl;
ret = s.count(100);
if (ret == 0)
cout << "100,该值不存在" << endl;
//find
set<int>::iterator it;
it = s.find(2);
if (it != s.end())
cout << *it << " 存在" << endl;
it = s.find(100);
if (it == s.end())
cout << "find(100),该值不存在!" << endl;
//erase
ret = s.erase(1);
if (ret == 1)
cout << "删除 1 成功!" << endl;
it = s.erase(s.find(4));
cout << "删除 4 成功,此时迭代器指向下一个元素:"<<*it <<" 的位置!"<< endl;
//size
cout << "s现在还有:" << s.size() << " 个元素" << endl;
//遍历
it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//clear和empty
s.clear();
if (s.empty())
cout << "clear(),s已经为空!" << endl;
system("pause");
return 0;
}
运行结果:
关于set的几个问题:
(1)为何map和set的插入删除效率比用其他序列容器高?
因为对于关联式容器来说,不需要做内存的拷贝和移动,map和set的元素都是以节点的方式来储存,结构和链表相似,所以插入和删除的时候只要改变指针的指向就可以了。
(2)为何每次insert之后,以前保存的iterator不会失效?
这是关于迭代器失效的问题;和vector一样,我们的每次插入和删除都有可能导致指针失效,所以我们在插入的时候,迭代器都指向当前插入的元素的位置,当删除一个元素后,此时该元素的内存已经不再或者被别人使用;所以我们就是迭代器就指向删除元素的下一个元素的位置。我们每次都不会使用过期的itreator。