C++之关联容器的学习(一)

在读C++Primer,这几天看到关联容器了,一下子感觉容器乃神器啊,可是内容也有点小多,所以在此梳理一下,以备后续查询方便

一、pair类型

pair类型是与关联容器密切相关的一种简单的标准库类型,该类型在utility头文件中定义。

1.pair的创建和初始化:

pair是一种模板类型,创建时必须提供两个类型名:pair对象所包含的两个数据成员各自对应的类型名字。

    例如:

pair<string, string> anon//存储两个string
pair<string, int> word_count;//存储一个string, 一个int
pair<string, vector<int> > line;//存储一个string, 一个vector类型。
 
以上创建时都未初始化,所以会自动调用默认构造函数初始化值,如上面的string会被初始化为空,int 被初始化为0,vector也为空。

下面是初始化:

pair<string, string> author("James", "Joyce");
pair类型使用相当麻烦,为此可用typedef简化其声明:

typedef pair<string, string> Author;
Author proust("Marcle", "Proust");
Author joyce("James", "Joyce");
如上,简化后使用方便了许多。

2.pair对象的操作:

pair类可以直接访问其成员,即,其成员是公有的,分别为first 和second,用点操作符-----成员访问标志即可访问其成员:

string firstbook;
if(author.first == "James" && author.second == "Joyce")
	firstbook = "Stephen Hero";
3.生成新的pair对象:

除了使用构造函数,还可以用make_pair函数,由传递给它的两个实参生成一个新的pair对象:

例如:

pair<string, string> next_auth;
string first, second;
while(cin >> first >> second)
	next_auth = make_pair(first, second);
二、关联容器:

(一).map:

Map是一个键—值对的集合,就像一个关联数组:键相当于数组的下标,而值相当于下标所对应存储的值,只不过map的键作为下标时不只是int, 可以使任何其他类型,比如:string。

1.定义:

使用map必须包含map头文件!分别指明键和值得类型即可:

map<string, int> word_count;
上面的声明表明,这个map类型是以string类型作为键值,即意义上的下标,int作为值存储。

注意:键类型唯一的约束就是,必须支持< 操作符,比如我们上面定义的word_count,键为string,满足<操作符,所以可用作map类型的键

2.map定义的类型:

map每个元素分为键以及键关联的值,map的value_type就反映了这个事实,value_type是存储元素的键以及值得pair类型,而且键为const。

例如,我们上面定义的word_count的value_type是pair<const string, int>类型。

(a).map迭代器进行解引用将产生pair类型的对象:

对迭代器解引用,将得到一个value_type类型的值。对于map,它是pair类型。

例如:

map<string, int>::iterator map_it = word_count.begin();
cout << map_it->first;
cout << " " << map_it->second;
map_it->first = "new key";
++map_it->second;
解引用得到一个pair对象,first成员存放键,为const,second成员存放值

3.使用下标访问map对象:

例如:

map<string, int> word_count;
word_count["Anna"] = 1;
这个是典型的用下标,即键值访问对象的值。如果该键已经在map中,则下标运算返回该键所关联的值;当该键不存在时,map会为该键创建一个新的元素,并将它插入map中。

注意:map迭代器返回value_type类型的值,包含const key_type和mapped——type类型成员的pair对象。而下标操作符则返回一个mapped_type类型的值

注:下标访问的副作用:当map中不包含该键时,会自动添加新元素!!!

我们可以利用这一副作用,例如下面的单词计数程序:

map<string, int> word_count;
string word;
while(cin >> word)
	++word_count[word];
这使得我们的程序异常简洁!

4.map::insert的使用:

(a).以insert代替下标运算:

直接使用insert成员函数,其语法更为紧凑:

word_count.insert(map<string, int>::value_type("Anna", 1));
它的实参是一个pair对象,因为value_type类型就是pair类型的同义词,insert的实参创建了一个pair对象,将该对象插入map容器。

注:使用insert成员函数可以有效避免下标操作的副作用:不必要的初始化。

另外,上面的实参略显臃肿,可以用下面的方法简化:

(1).使用make_pair

word_count.insert(make_pair("Anna", 1));
(2).使用typedef

word_count.insert(valType("Anna", 1));

这两种方法都大大简化了代码,提高了程序的可读性。

(b).检测insert的返回值:

由于map中一个键只对应一个元素,如果试图插入的元素已经在容器中,则insert函数将不做任何操作。因此,含有一个或一对迭代器的形参的Insert函数不能说明有多少元素插入容器其中!

但是,带有一个pair形参的insert版本将返回一个值:包含一个迭代器和一个bool值得pair对象,其中,迭代器指向map中具有相应键的元素,而bool值表示是否插入该元素。

如果该键已在容器中,则关联的值不变,返回的bool值为false;如果不在容器中,则插入新元素,bool值变为true。这两种情况下,迭代器都将指向具有给定键的元素。

例如:下面是一个用insert重写的单词计数程序:

	map<string, int> word_count;//定义一个map变量 
	string word;
	while(cin >> word) 
	{
		//ret是一个人pair变量,insert函数返回一个pari变量,将返回值赋给ret...
		//pair的第一个成员是一个map类型的迭代器,保存insert返回的指向插入元素的迭代器, 
		pair<map<string, int>::iterator, bool> ret = word_count.insert(make_pair(word, 1)); 
		if(!ret.second)
			++ret.first->second;
	}
	
5.查找并读取map中的元素:

因为用下标查找时,容器会自动插入一个不存在该键值的元素,所以不适合查找。

(a).使用count检查某键是否存在

对于map而言,count的返回值不是1就是0,因为map只允许一个键对应一个值,所以count可以有效的表明一个键是否存在!如果返回值非0,则这时可放心的用下标访问该元素而不必担心会插入新元素。

int occurs = 0;
if(word_count.count("foobar"))
	occurs = word_count["foobar"];
然而, 执行完count后再用下标,实际上是对元素进行了两次查找,若希望当元素存在时就使用它,应该用下面的find操作。

find操作返回指向元素的迭代器,若元素不存在,则返回end迭代器。

如果希望当具有某键的元素存在时就获取该元素的引用,否则就不在容器中创建该元素,那么应该使用find。

int occurs = 0;
map<string, int>::iterator it = word_count.find("foobar");
if(it != word_count.end())	
	occurs = it->second;
6.从map中删除元素

m.erase(k) //删除m中键为k的元素。返回size_type类型的值,表示删除的元素个数
m.erase(p) //删除m中迭代器p指向的元素,p必须指向m中确实存在的元素,而且不能等于m.end()。返回void类型 
m.erase(b, e) //删除迭代器区间里的值,返回void类型 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值