set集合容器:集合(Set)是一种包含已排序对象的关联容器。所谓关联容器就是通过键(key)来读取和修改元素。与map关联容器不同,它只是单纯键的集合。set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。实现了红黑树的平衡二叉检索树的数据结构,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值.

注:平衡二叉检索树使用中序遍历算法,检索效率高于vector、deque和list等容器,另外使用中序遍历可将键值按照从小到大遍历出来。

set/multiset会根据待定的排序准则,自动将元素排序。两者不同在于前者不允许元素重复,而后者允许。
1) 不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素
2) 不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取,而且从迭代器角度来看,元素值是常数
3) 元素比较动作只能用于型别相同的容器(即元素和排序准则必须相同)
set模板原型://Key为元素(键值)类型
template <class Key, class Compare=less<Key>, class Alloc=STL_DEFAULT_ALLOCATOR(Key) >
从原型可以看出,可以看出比较函数对象及内存分配器采用的是默认参数,因此如果未指定,它们将采用系统默认方式。

//set容器的每一个键只能对应一个元素,即不存在键相同的不同元素。
#include<iostream>
#include<set>
using namespace std;
void TestSet()
{
	set<int> s;
	s.insert(1);
	s.insert(2);
	s.insert(4);
	s.insert(3);
	s.insert(7);
	s.insert(6);

	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << "  ";
		++it;
	}
	cout << endl;
}

wKiom1ehoj7ioLrhAAApPacWB-I133.png

insert(key_value); 将key_value插入到set中 ,返回值是pair<set<int>::iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置,若key_value已经在set中,则iterator表示的key_value在set中的位置,pair的second为false。

inset(first,second);将迭代器first到second之间的元素插入到set中,返回值是void.



wKioL1eho5Sy5A3UAABSkTp7TGo391.png


for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
std::cout<< *it << ",";
}
std::cout<< std::endl;
std::set<int>st(vec.begin(), vec.end());
std::cout<< "set : " << std::endl;
for(std::set<int>::iterator it = st.begin(); it != st.end(); ++it) {
std::cout<< *it << ",";
}

insert()的参数既可以是一个键,也可以是一对迭代器,它们都可以实现向set容器中添加元素,只不过函数的返回值不同。另外,可以看出向set容器中添加元素后,它会自动排序。

与map容器不同,set容器不支持下标操作访问元素。

使用count()函数可以查询元素是否存在,如果查询的元素存在则返回1,反之则0。使用find()函数,如果查询的元素存在则返回指向该元素的迭代器,反之则返回超出末端迭代器。

count() 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。

wKiom1ehpB3zyWHcAAAakBCG-K4182.png

erase(iterator)  ,删除定位器iterator指向的值

erase(first,second),删除定位器first和second之间的值

erase(key_value),删除键值key_value的值

find()  ,返回给定值值得定位器,如果没找到则返回end()。

void TestMultiSet()
{
	multiset<int> s;
	s.insert(1);
	s.insert(4);
	s.insert(1);
	s.insert(9);
	s.insert(8);
	s.insert(9);
	multiset<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << "  ";
		++it;
	}
	cout << endl;
	
	it = s.find(9);
	if(it != s.end())
		s.erase(ret);//全部删除9

}

wKioL1ehpM7QEMUEAAA9TV55doo659.png