set/multiset容器

set容器基本概念
set的特性是,所有元素都会根据元素的键值自动被排序,set的元素不像map那样可以同时拥有实值和键值,set的元素既是键值又是实值,set不允许两个元素有相同的键值。
我们可以通过set的迭代器改变set元素的值吗?不行,因为set元素值就是其键值,关系到set元素的排序规则,如果任意改变set元素值,会严重破坏set组织,换句话说,set的Iterator是一种const_iterator。
set拥有和list某些相同的性质,当对容器中的元素进行插入操作或者删除操作时,操作之前的所有迭代器,在操作完成之后依然有效,被删除的那个元素的迭代器必然是一个例外。

multiset容器基本概念
multiset特性及用法和set容器完全相同,唯一的差别在于它允许键值重复,set和multiset的底层实现是红黑树,红黑树为平衡二叉树的一种。
树的简单知识
二叉树就是任何结点最多只允许有两个子节点,分别是左子节点,和右子节点。
set/multiset容器_第1张图片 二叉搜索树,是指二叉树中的节点按照一定的规则进行排序,使得对二叉树中元素的访问更加高效。二叉搜索树的放置规则是:任何结点的元素值一定大于其左数中的每一个节点的元素值,并且小于其右子树的值。因此从根节点一直向左走,一直到无路可走,即得到最小值,一直向右走,直至无路可走,可得到最大值,那么在二叉搜索树中找到最大元素和最小元素是非常简单的事情。下图为二叉搜索树。
set/multiset容器_第2张图片 上面我们介绍了二叉搜索树,那么当一个二叉搜索树的左子树和右子树不平衡的时候,那么搜索依据上图所示,搜索9所花费的时间比搜索17所花费的时间要多,由于我们的输入或者经过我们插入或者删除操作,二叉树失去平衡,造成搜索效率降低。
所以我们有了一个平衡二叉树的概念,所谓的平衡不是指完全平衡
所有的左子节点与右子节点的查找不能大于1.
set/multiset容器_第3张图片set常用API

set构造函数:
setst; //set默认构造函数
multisetmst; //multiset默认构造函数
set(const set&st); //拷贝构造函数

set赋值操作
set& operator = (const set& st); //重载等号运算符
swap(st); //交换两个集合容器

set大小操作
size(); //返回容器中元素的数目
empty(); //判断容器是否为空

set插入和删除操作:
insert(elem); //在容器中插入元素
clear(); //清除所有元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end); //删除区间(beg,end)的所有元素,返回下一个元素的迭代器
erase(elem); //删除容器中值为elem的元素

set查找操作:
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回set.end()
count(key); //查找键key的元素的个数
lower_bound(keyElem); //返回第一个key>=keyElem元素的迭代器
upper_bound(keyElem); //返回第一个key>keyElem元素的迭代器
equal_range(keyElem); //返回容器中key与keyElem相等的上下限的两个迭代器

//An highlighted block
void print(set<int> &s)
	{
	for(set<int>::iterator it = s.begin();it != s.end();it++)
		{
			cout << *it << " ";
		}
	cout << endl;
	}
void test1()
	{
		set<int>s1;
		//关联式容器 key进行排序,从小到大
		s1.insert(5);
		s1.insert(1);
		s1.insert(7);
		s1.insert(3);
		s1.insert(9);
		print(s1);

		if(s1.empty())
			{
				cout << "s1为空" << endl;
			}
		else
			{
			cout << "s1的大小:" << s1.size() << endl;
			}
		//删除
		s1.erase(s1.begin());
		s1.erase(3);
		print(s1);
	}

set/multiset容器_第4张图片

//An highlighted block
void test2()
	{
	set<int>s1;
	s1.insert(5);
	s1.insert(1);
	s1.insert(7);
	s1.insert(3);
	s1.insert(9);

	//对于set没有value    key就是value

	set<int>::iterator pos = s1.find(3);
	//判断是否找到
	if (pos != s1.end())
	{
		cout << "找到了,值为:"  << *pos << endl;
	}
	else
	{
		cout << "未找到" << endl;
	}

	//查找键key的元素的个数   对于set而言  结果是0或者1

	int num = s1.count(1);
	cout << "1的个数为:" << num << endl;

	//lower_bound(keyElem);	//返回第一个key >= keyElem元素的迭代器
	set<int>::iterator key_pos = s1.lower_bound(3);
	if (key_pos != s1.end())
	{
		cout << "找到了  lower_bound(3)的值为:" << *key_pos << endl;
	} 
	else
	{
		cout << "未找到" << endl;
	}

	//upper_bound(keyElem);	//返回第一个key > keyElem元素的迭代器
	set<int>::iterator Upper = s1.upper_bound(3);
	if (Upper != s1.end())
		{
		cout << "找到了 upper_bound(3)的值为:" << *Upper << endl;
		} 
	else
		{
		cout << "未找到" << endl;
		}


	//equal_range(keyElem);	//返回容器中key与keyElem相等的上下限的两个迭代器
	//上下限就是lower_bound和upper_bound
	pair<set<int>::iterator,set<int>::iterator> ret = s1.equal_range(3);
	//获取第一个值
	if (ret.first != s1.end())
	{
		cout << "找到equal_range中lower_bound的值:" << *(ret.first) << endl;
	}
	else
	{
		cout << "未找到 " << endl;
	}

	//获取第二个值
	if (ret.second != s1.end())
	{
		cout << "找到equal_range中upper_bound的值:" << *(ret.second) << endl;
	} 
	else
	{
		cout << "未找到" << endl;
	}

	}

set/multiset容器_第5张图片

//An highlighted block
//创建对组
void test3()
	{
		//第一种
		pair<string,int> p(string("Tom"),100);

		//取值
		cout << "姓名:" << p.first << endl;
		cout << "年龄:" << p.second << endl;


		//第二种
		pair<string,int> p2 = make_pair("Jerry",200);
		cout << "姓名:"  << p2.first << endl;
		cout << "年龄:"  << p2.second << endl;
	}

set/multiset容器_第6张图片

//An highlighted block
//set容器不允许插入重复的键值
//set插入返回值是 pair<迭代器,是否成功指示>
void test4()
	{
		set<int> s;
		s.insert(10);
		


		pair<set<int>::iterator,bool> ret = s.insert(10);
		if (ret.second)
		{	
			cout << "第二次插入成功" << endl;
		} 
		else
		{
			cout << "第二次插入失败" << endl;
		}
		print(s);
	}

set/multiset容器_第7张图片

//An highlighted block
//指定set排序规则  从大到小
//仿函数
class myCompare
	{
	public:
		//重载()
		bool operator() (int val,int val2)
			{
				return val > val2;
			}
	};




//set容器排序
void test5()
	{
	set<int>s1;
	s1.insert(5);
	s1.insert(1);
	s1.insert(7);
	s1.insert(3);
	s1.insert(9);
	print(s1);		


	//从大到小排序
	//在插入前就指定排序规则
	set<int,myCompare> s2;
	s2.insert(5);
	s2.insert(1);
	s2.insert(8);
	s2.insert(4);
	s2.insert(-1);
	for (set<int,myCompare>::iterator it = s2.begin();it != s2.end();it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	}

set/multiset容器_第8张图片

//An highlighted block
//自定义数据类型
class Person
	{
	public:
		Person(string name,int age)
			{
				this ->_name = name;
				this ->_age = age;
			}
	
		string _name;
		int _age;
	};

class _compare_person
	{
	public:
	bool operator()(const Person & p1,const Person & p2)
		{
			if (p1._age < p2._age)		//年龄升序
			{
				return true;
			}
			return false;
		}
	};

void test6()
	{
		//插入自定义数据类型,要先指定好排序规则
		set<Person,_compare_person> s;
		Person p1("tom",20);
		Person p2("jerry",30);
		Person p3("bob",18);
		Person p4("hanmeimei",14);
		Person p5("tom",23);

		s.insert(p1);
		s.insert(p2);
		s.insert(p3);
		s.insert(p4);
		//实验发现一个有趣的现象,若是按照年龄排序,则年龄相同的无法插入,但是姓名相同年龄不同的可以插入
		pair<set<Person,_compare_person>::iterator,bool> ret = s.insert(p5);
		if (ret.second)
		{
			cout << "yes" << endl;
		} 
		else
		{
			cout << "No" << endl;
		}

		

		for (set<Person,_compare_person>::iterator it = s.begin();it != s.end();it++)
		{
			cout << "姓名:" << it ->_name << "  年龄:" << it ->_age << endl;
		}

	}

set/multiset容器_第9张图片

你可能感兴趣的:(c++)