文章目录
- map的概念
- map的使用
- 构造![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/30e9a697b50d47a591af6e9ae2bbb7d7.png)
- insert
- 迭代器+遍历
- find
- operator[]
- 举例
map的概念
map是一个关联容器,里面的每一个位置pair,会存储两个值,一个是key,另一个是value.
我们可以通过搜索key得到value.
比如英语翻译的软件:输入一个英语单词 left(key),就能得到翻译 左边(value).
事实上,英语翻译软件底层也就是这样.
map的使用
构造
map<string, string> dict;
首先,map的构造需要我们传至少两种类型.
比如上面Key是string,T是string.
insert
//构造有名对象
pair<string, string> kv1 = { "left","左边" };
dict.insert(kv1);
//构造匿名对象
dict.insert(pair<string, string>("right", "右边"));
//函数传参
dict.insert(make_pair("sort", "排序"));
//隐式类型转化
dict.insert({ "string", "字符串" });
map中为了使得两个值key-value关联到一起,会把它们绑定成一个类.
map的插入推荐用最后一种,隐式类型转化.
隐式类型转化本质是就是在传参时构造一个pair的临时对象,与上面构造匿名对象等类似.
迭代器+遍历
void test_map1()
{
map<string, string> dict;
//构造有名对象
pair<string, string> kv1 = { "left","左边" };
dict.insert(kv1);
//构造匿名对象
dict.insert(pair<string, string>("right", "右边"));
//函数传参
dict.insert(make_pair("sort", "排序"));
//隐式类型转化
dict.insert({ "string", "字符串" });
map<string, string>::iterator it = dict.begin();
while (it != dict.end())
{
cout << it->first << ":" << it->second << endl;
//cout << it.operator->()->first << ":" << it.operator->()->second << endl;
it++;
}
}
map的迭代器使用和vector等容器类似.但是因为map里面存储的是键值对<key,value>,所有打印起来比较麻烦.
cout << it->first << ":" << it->second << endl;
//cout << it.operator->()->first << ":" << it.operator->()->second << endl;
这两行代码可能理解起来稍微复杂一点.
key是first,value是second,这里是按照存储顺序排列.
我们一个键值对<key,value>和其他一堆东西的组合想象成一个节点.it是一个指针,指向这个节点.
map类里面写的运算符重载it.operator->()会返回键值对<key,value>的指针,用这个指针可以指向key和value.我们在使用可以直接省略.operator->().
理解了这个,就能更好的理解下面的范围for
for (auto& e : dict)
{
cout << e.first << ":" << e.second << endl;
}
e相当于键值对<key,value>的引用.这个的底层和上面类似.只不过在书写方面简单一些.
find
//map<string, string>::iterator pos = dict.find("left");
auto pos = dict.find("left");
if (pos != dict.end())
{
cout << pos->first << ":" << pos->second << endl;
}
find输入key值,找到会返回该节点的迭代器,找不到会返回迭代器的终点dict.end().
operator[]
operator[]是map里面内置的最强的函数,在我们刷题时帮助巨大.
首先看看operator的底层
//V& operator[](const K& key)
//{
// pair<iterator, bool> ret = insert({ key ,V() });
// iterator it = ret.first;
// return it.second;
//}
operator[]会调用insert函数,insert函数里面传key值和value的默认构造.
不管插入是否成功,都会返回键值对pair<iterator, bool>,
bool里面表示插入成功与否,
iterator则返回key值所在的节点的迭代器.我们取得这个迭代器,然后返回value的引用.
void test_map2()
{
//string可以直接构造字符串数组
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" };
map<string, int> kv;
//按字典序排序
for (auto& e : arr)
{
//V& value=kv[e] value++;
kv[e]++;
}
for (auto& e : kv)
{
cout << e.first << ":" << e.second << endl;
}
}
举例
leetcode: 692. 前K个高频单词
在计算单词出现次数时,要把单词和出现次数链接起来,就得用到map.
class Solution {
public:
//仿函数,控制比较逻辑
struct Com
{
//出现次数大的在前面,一样按照字典序小的在前面.
bool operator()(pair<string,int>& p1,pair<string,int>&p2)
{
return p1.second>p2.second
|| (p1.second==p2.second && p1.first<p2.first);
}
};
vector<string> topKFrequent(vector<string>& words, int k) {
map<string,int> m;
for(auto& e:words)
{
//map里面的[]调用insert函数,这个函数会返回第二个值的引用
m[e]++;
}
//把map里面的键值对存到vector进行排序
vector<pair<string,int>> vp(m.begin(),m.end());
//函数模板要传对象
sort(vp.begin(),vp.end(),Com());
vector<string> ret;
for(size_t i=0; i<k; i++)
{
ret.push_back(vp[i].first);
}
return ret;
}
};