C++关联容器

1.关联容器是通过关键字来保存和访问数据的。关联容器分为两大类:map和set。其中,map是通过键值对来操作的,这里的键就是关键字,值就是对应的数据。

例如:

map<int ,int> m;定义了一个空的map变量m,它的关键字类型是int,关键字对应的值的类型是int。可以将map理解成为函数,关键字是自变量,关键字对应的值是因变量。

set,这是一个集合类。它的关键字和值是相同的。也就是说定义了一个set,它的关键字和值是同一个值。例如:

set<int> s;定义了一个空的set类型的变量s,它里面可以存储int类型的数据,它的关键字和值都是同一个,类型都是int。set和数学上的集合是一样的,都有一个特点,唯一性。也就是说,set中的元素,一般不能重复出现。因此,我们有时候使用set,来判断一个关键字是否在一个某一个集合中。

2.map和set有很多种类:它们通过前面的修饰词来加以区分。修饰词主要有:unordered,multi,一个表示无序,另外一个表示关键字可以重复。例如:unordered_multiset表示,一个无序的,关键字可以重复的set。这里的无序的实现数据结构是哈希函数。

map和set都是模板。

3.关于定义关联容器,可能当你去读C++ primer这本书时,会发现,在定义关联容器时有好多方法。其实,通过我的时间发现,这和你的编译环境,编译器是有很大的联系的,又看看,你的编译器对C++11支持多少。

例如:

定义:map<string,string> word={ {"A","a"},{"B","b"}};//对于这样的定义,不同的编译器,编译之后的结果也是不一样的。想VS2012好像就不能支持。

4.因为,关联容器的关键字和对应值的类型,没有强制的限制,也就是说,自己定义的类也可以当做关键词或者对应的值的类型来使用,但是,我们要注意,无论哪一种类型,要支持比较运算符<,或者要支持比较方法。如果不支持,麻烦自定义。

5.pair类型:

在之前我们说cocos2dx中读取excle文件时,最后提到了pair类型,这里我们对其进行更加详细的说明。

pair类型,这是一个标准库类型。pair类型,保存两个数据,在初始化的时候,需要传递两个类型。pair的两个数据成员是公共的。

6.关联容器的操作:

6.1额外的类型别名:

value_type:对于set来说,这个和关键字的类型是一样的。对于map来说,这个的类型是:pair<const key_type,mapped_type>

例如:

map<int ,int >::value_type var;//var的类型就是pair<const int,int>。

mapped_type:每个关键词关联的类型。这个只使用与map,说白了,就是值的类型

例如:map<int ,int >::mapped_type var;//var的类型就是int

key_type:就是关键字的类型

6.2关于map的操作.

6.2.1要向map中添加元素,这个元素的类型,必须是pair类型。正如上面所说的,map中value_type是pair类型。因此,就像之前讲过的,要构造一个pair类型的数据,例如:make_pair<i,j>这就是构造一个pair类型的数据。

例如:

	map<int,int> m1;//不能重复关键字
	auto it=m1.begin();
	map<int ,int>::key_type i;
	int j=10;
	for(int i=0;i<10;i++)
	{
		auto p=m1.insert(make_pair(i,j));
		j++;
	}
添加元素,使用函数insert()。


但是,要特别注意:insert的返回值问题。

	template<class _Valty>
		typename enable_if<is_convertible<_Valty, value_type>::value,
			_Pairib>::type
		insert(_Valty&& _Val)
		{	// try to insert node with value _Val, favoring right side
		_Nodeptr _Newnode = this->_Buynode(_STD forward<_Valty>(_Val));
		return (_Insert_nohint(false,
			this->_Myval(_Newnode), _Newnode));
		}
上面是insert的源码。编译环境VS2012

insert返回的值依赖于容器类型和参数。

如果是关键字不能重复的,insert返回一个pair类型值。这个值的first数据成员保存的是一个指向要插入元素的迭代器,second数据成员,是一个bool值,用来表示要插入的值,是否插入成功。

例如:

	map<int,int> m1;//不能重复关键字
	auto it=m1.begin();
	map<int ,int>::key_type i;
	int j=10;
	for(int i=0;i<10;i++)
	{
		auto p=m1.insert(make_pair(i,j));
		if(p.second)
			cout<<"插入的值:"<<p.first->second<<endl;
		j++;
	}
在这段代码中,我们将i,j插入到map中。在这里,p的类型就是一个pair类型.first数据成员,是一个迭代器,指向插入元素的一个迭代器。这个迭代器中,存放的就是要插入的这两个数i和j的值。p的second元素是一个bool类型的数据,表示是否插入成功。

这段代码,单步调试的结果:


最后的结果值:


6.2.2其次,就是迭代器的问题。

当解引用一个关联容器的迭代器是,我们将得到一个值的value_type的一个引用。

在map中,value_type是一个pair。而且,first还是const类型的,所以,不能修改first指向的数据。

在set中,set和map差不多,也是只能读取,不能修改。

例如:

	for(auto it=m1.begin();it!=m1.end();it++)
	{
		cout<<"first:"<<it->first<<"second:"<<it->second<<endl;

要注意,当使用迭代器遍历map和set时,迭代器是按照关键字的升序顺序来遍历的。

6.2.3 删除元素。

删除元素,使用ereas函数,传入的参数可以是关键字,迭代器,迭代器的范围。也就是说,通过这个函数,可以删除一个范围的元素。

例如:

m1.erase(1);//删除对应关键词的元素

这一步操作之后,会将关键字为1,这个键值对删除。

6.2.4下标运算符和访问元素

map是可以支持下标运算符的。set是不支持下标运算符的。

例如,之前定义的m1这个变量,如果,我们这样操作:m1[11]。显然,我们没有11这个关键字,但是如果使用下标运算符之后,他会将11这个关键字添加到m1这个map中,而且,还会初始化。

因此,我们要知道,一个关键字,是否在一个map中,最好使用find和cout函数。

这两个函数的源码:

	// 返回关键字的个数
	//	size_type count(const key_type& _Keyval) const
	//	{	// count all elements that match _Keyval
	//	_Paircc _Ans = equal_range(_Keyval);
	//	size_type _Num = 0;
	//	_Distance(_Ans.first, _Ans.second, _Num);
	//	return (_Num);
	//	}
	p.count(1);
count这个函数,是判断这个关键字在map中,是否存在,而且,存在几个。

	//这个函数适合检查该元素是否在关联容器中,传递的参数是关键词的类型
	//源码
		//iterator find(const key_type& _Keyval)
		//{	// find an element in mutable sequence that matches _Keyval
		//iterator _Where = lower_bound(_Keyval);
		//return (_Where == end()
		//	|| _DEBUG_LT_PRED(this->_Getcomp(),
		//		_Keyval, this->_Key(_Where._Mynode()))
		//			? end() : _Where);
		//}
	auto temp= p.find(1);

find函数,只关心关键字是否存在在map中。


这就是今天我们要和大家分享的关于C++关联容器的知识,欢迎大家指正!



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值