STL之关联容器(pair、map、set的使用)

1.关联容器与顺序容器的对比

1)关联容器是通过键存储和读取元素,而顺序容器则是通过元素在容器中的位置顺序存储和访问元素

2)物理存储方式:一般关联容器是非连续内存存储,而顺序容器一部分是连续存储在内存中,随机访问速度较快,如vector、deque

关联容器一般包括map、set两种基本的关联容器:

【map】关联数组,元素通过键来存储和读取;适用于需要存储/修改每个键所关联的值的情况

【set】大小可变的集合,支持通过键实现的快速读取;希望有效地存储不同值的集合

map和set不允许为同一个键添加第二个元素,但是还有支持一个键对应多个实例的multimap和multiset类型:

【multimap】支持同一个键多次出现的map类型

【multiset】支持同一个键多次出现的set类型

2.pair类型

pair类型的操作

pair<T1, T2>p1;  //创建一个空的pair对象,它的两个元素类型分别为T1、T2,采用值初始化

pair<T1, T2>p1(v1, v2); //创建一个pair对象,first成员被初始化为v1,second成员被初始化被v2

make_pair(v1,v2); //v1,v2创建一个新的pair对象,其元素类型分别是v1,v2的类型

p1 < p2; //两个pair对象之间的小于运算,其定义遵循字典次序

p1 == p2; //如果两个pair对象的first和second成员依次相等,则两个对象相等

p.first; //p中的first的公有数据成员

p.second; //p中的second的公有数据成员

1)pair的创建和初始化,与顺序容器类似,如下:

	pair<string, string> anon;//调用默认构造函数来初始化
	pair<string, int> word_count;
	pair<string, vector<int>> line;

	pair<string, string> author("jim", "weshon"); //定义时提供初始化
	typedef pair<string, string> Author;
	Author product("marcel", "Product");
2)pair对象的操作,支持== 、< ,first、second成员的访问,如下

	string firstbook;
	if (author.first == "jim" && author.second == "weshon")
	{
		firstbook = "stephon hero"; //
	}
3)生成新的pair对象,如下:
	pair<string, string> next_author;
	string first, second;
	while (cin >> first >> second)
	{
		next_author = make_pair(first, second);
		//pair<string, string> next_author(first, second); //与上面创建类似
	}

3. map容器

map的构造函数:

map<k,v>; //创建一个名为m的空map对象,其键和值的类型分别为k和v

map<k,v>m(m2); //创建m2的副本m,m与m2必须具有相同的键类型和值类型

map<k,v>m(b,e); //创建map类型的对象m,存储迭代器b和e标记的范围内的所有元素的副本,元素的类型必须能转换为pair<const k, v>

map中键类型的约束,键必须支持“<”操作符,键不允许修改

map<k,v>::key_type //索引的键的类型

map<k,v>::mapped_type //键所关联的值的类型

map<k,v>::value_type //pair类型,first成员具有map<const k, v>::key_type类型,second成员具有map<const k, v>::mapped_type类型

1)map对象的定义,支持如下几种:

	map<string, int> word_count;
	map<string, list<size_t>> line_count;
	map<vector<int>::iterator, int> vcmap;
	//map<list<int>::iterator, int> lsmap; //error, list can't support < operator
以上为map<key, value> m; 的构函类型

注意:键一定要支持"<"操作符, 如上list就不支持操作符<

2)map迭代器的使用,如下

	map<string, int>::iterator map_iter = word_count.begin(); //iter: pair<const string, int>
	cout << map_iter->first << " " << map_iter->second << endl;
	//map_iter->first = "new key"; // error key is const, can't copy
	map_iter->second ++;
map的迭代器键类型为const,如上键类型为pair<const string, int>

3)下标访问元素对象,如果不存在,就会创建一个新元素

	word_count["jim"] = 1;
	word_count["sun"] = 1;
由于在这两个之前,没有插入任何元素,所以这两个操作都会插入,如下正确的使用迭代器才是必须的:
	cout << "inset map data: key value"<< endl;
	string word;
	while (cin >> word)
	{
		if (word == "@") break;
		++word_count[word];
	}
	map_iter = word_count.begin();
	for ( ; map_iter != word_count.end(); ++map_iter)
	{
		cout << map_iter->first << " " << map_iter->second << endl;
	}
将重复出现的键的值+1,新出现的键直接插入,并将值置为1,可以计算相同元素出现的次数

4)map插入元素

m.insert(e); //e是m上的value_type类型,如果键不在m中,则插入新元素,在的话,保持m不变;返回值为一个pair类型的对象,包含指向键位e.first的元素的map迭代器以及一个bool类型的对象,表示是否插入了该元素

m.insert(beg,end); //beg和end标记元素范围的迭代器,元素类型必须为m.value_type,返回值为void

m.insert(iter,e); //e是一个用在m上的value_type类型的值,不在插入以iter为起点搜索新元素的位置;返回值为一个迭代器指向m中具有给定元素键的元素

	string word = "";
	while (cin >> word)
	{
		if (word == "@")
			break; 
			
		//word_count.insert(map<string, int>::value_type("Anna", 1));
		//word_count.insert(make_pair("Jim", 1));
		//typedef map<string, int>::value_type valType;
		//word_count.insert(valType("COM", 1));
		pair<map<string, int>::iterator, bool> ret = word_count.insert(make_pair(word, 1));
		if (!ret.second)
		{
			++ret.first->second;
		}
		//++word_count[word];
	}

(1)使用insert可以避免下标操作所带来的副作用,不必要的初始化

(2)检测返回值,带有一个简直pair形参的inset版本将返回一个值:包含一个迭代器和一个bool值的pair类型;其中迭代器指向map中具有相应键的元素,而bool表示是否插入了该元素。如果存在不插入,返回false,不存在则插入,返回true,但是迭代器都将指向具有给定键的元素。

5)查找并读取元素

前面已经讲过下标操作能访问和读取元素,但是副作用很严重。map容器提供了两个操作:count和find

m.count(k);返回m中k的出现次数

m.find(k);如果m容器中存在按k索引的元素,则返回指向该元素的迭代器;不存在的话,返回超出末端的迭代器

	if (word_count.count("jim"))
	{
		cout << "jim = " << word_count["jim"] << endl;
	}
	
	map_iter = word_count.find("tom");
	if (map_iter != word_count.end())
	{
		word_count["tom"] = 250;
		cout << "tom = " << map_iter->second << endl;
	}

6)删除元素

m.erase(k); //删除m中关键字为k的元素;返回size_type类型的值,表示删除的元素个数

m.erase(p); //删除m中迭代器p指向的元素;p必须存在,且不等于m.end();返回void类型

m.erase(b,e); //删除一段范围内的元素,由迭代器b和e标记;返回为void类型

word_count.erase("jim");
map返回值只可能是0或者1,返回0表示不存在

7)map对象的迭代遍历

map<string, int>::iterator map_iter = word_count.begin(); //iter: pair<const string, int> 上面已有

	map_iter = word_count.begin();
	for ( ; map_iter != word_count.end(); ++map_iter)
	{
		cout << map_iter->first << " " << map_iter->second << endl;
	}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值