来看一道题:请统计数组strs里各个字符出现的次数。(使用map)
string strs[] = { “sort”, “sort”, “second”, “sort”, “first”, “first” };
那么最直观,最容易想到的方法,就是用first来存字符,second来存次数。
map<string, size_t> countMap;//first为string类型存字符,second为size_t类型存次数
for (size_t i = 0; i < sizeof(strs) / sizeof(strs[0]); i++)
{
map<string, size_t>::iterator it = countMap.find(strs[i]);
//map的find:如果找到,返回该节点的迭代器,如果没有找到,返回end
if (it != countMap.end())//之前已经存在,那么second++
{
it->second++;
}
else//之前没有,则插入
{
countMap.insert(make_pair(strs[i], 1));//make_pair是模板函数,自动推演类型,不用多写类型
}
}
这样简单易懂的方法,不需多说,那么接下来,看一下map的insert到底是怎么实现的呢?
pairbool> insert (const value_type& val);
可以看到,返回值为pair,first是迭代器,second为bool值。
阅读文档,可知:
如果插入之前没有的值,那么iterator指向插入之后的该节点,true
如果插入之前已经有的值,那么iterator指向本来存在的该节点,false
例如:
map<string, size_t> countMap;
pair<map<string, size_t>::iterator, bool> ret = countMap.insert(make_pair("sort", 1))
因为countMap里之前没有”sort”,所以顺利插入,ret的first指向该节点,second为true。
继续插入:
pair<map<string, size_t>::iterator, bool> ret2 = countMap.insert(make_pair("sort", 2));
此时”sort”已经存在,所以ret的first指向之前的节点,second为false。
现在已经了解了insert的用法,那么刚才的第一中方法就有一些不好,因为insert一定是查找了,find也是查找了,所以效率不够高。
基于对insert的理解,我得出了第二种方法:
for (size_t i = 0; i < sizeof(strs) / sizeof(strs[0]); i++)
{
pair<map<string, size_t>::iterator, bool> ret = countMap.insert(make_pair(strs[i], 1));
if (ret.second == false)
{
ret.first->second++;//ret.first是指向该节点的迭代器,ret.first->second表示该节点出现的次数
}
}
ret是pair类型,插入之后:first为指向strs[i]的迭代器,second为是否成功
如果str[i]不存在,iterator指向插入之后的节点,bool为true,iterator指向的second为1
如果str[i]存在,iterator指向本来存在的节点,但是本来存在的second并没有++,所以需要手动++
这个方法确实不错,接下来介绍重头戏,operator[]
mapped_type& operator[](const key_type& k)
{
return (*((this->insert(make_pair(k, mapped_type()))).first)).second;
}
mapped_type是V类型,所以mapped_type()就是调用V类型的默认构造函数; key_type是K类型。‘
仔细看这段代码:
他的意思是插入first为传入的k,second为该类型的默认值之后返回的pair,它的first指向k的节点的迭代器,second为true或是flase,接着取first的解引用,那么它的first实际上就是k,second就是V类型的默认值。
那么知道了这点,看看这样插入怎么样:
dict["sort"] = "排序"
insert的返回值里first指向构造的节点,该节点的first为”sort”,second为string默认值,然后将second赋值为”排序”。
那么这道题就有了第三种解法:
for (size_t i = 0; i < sizeof(strs) / sizeof(strs[0]); i++)
{
++countMap[strs[i]];
}
首先这是正确的:
首先operator[],插入了strs[i],成功或者失败,然后得到了该节点的second,出现一次就++一次,那么就可以统计出来次数。
这就是map的operator[]的用法。