6.4 map的常用函数
将任意基本类型(包括STL)映射到任意基本类型(包括STL)上,形成有序键值对<key,value>。键唯一。
实现:红黑树。
头文件:#include <map>
和 using namespace std;
6.4.1 map的定义
map<typename1,typename2> mp;
// example
map<int,vector<string> > mp;
map<set<string>,int> mp;
【注】字符串必须使用string
,不能使用字符数组。
6.4.2 map内元素的访问
1. 下标访问
map<char,int> mp;
printf("%d",mp['c']);
2. 迭代器访问
map<typename1,typename2>::iterator it;
其中,it->first
访问键,it->second
访问值。
6.4.3 map常用函数
1. 查找元素
- find()
find(key)
返回键为key
的映射的迭代器,时间复杂度为O(logn)。
如果key
不在mp
中,则find
返回迭代器 mp.end()
。
map<int,int>::iterator it=mp.find(2);
if(it!=mp.end())
{
cout<<"find success!"<<endl;
}
else
{
cout<<"find failed!"<<endl;
}
- count()
count("key")
返回元素出现的次数,缺点是无法定位元素出现的位置。由于map是一对一的映射,所以count("key")
的返回值要么是1,要么是0。
map<string,int> my_map;
my_map["first"]=1;
cout<<my_map.count("first")<<endl; //输出1;
2. 删除元素
- erase()
- 删除单个元素
根据迭代器删除元素,时间复杂度为O(1)。
map<int,string>::iterator it;
it=mp.find(1);
mp.erase(it);
- 删除单个元素
根据键删除元素,时间复杂度为O(logn)。
mp.erase(key)
- 删除一个区间内的元素
根据迭代器删除区间元素。删除[first,last)
区间的所有元素。时间复杂度为O(last-first)。
mp.erase(first,last)
- 清空整个map
mp.erase( mp.begin(), mp.end() );
3. 获取键值对的数量
- size()
获得map中键值对的对数。复杂度为O(1)。
int cnt=mp.size();
4. 清空
- clear()
清空map。复杂度为O(n)。
mp.clear();
- erase()
通过erase()清空map,复杂度为O(n)。
mp.erase( mp.begin(), mp.end() );
6.4.4 map的常见用途
- 建立字符与整数之间的映射(或者其他数据类型之间的映射)。
- 判断大整数或其他类型数据是否存在,作为bool数组。
6.4.5 例题
【例】1054 The Dominant Color
ATTENTION
- 看题的时候奇怪有两种判断:出现最多的或者超过半数的。
看了柳神的思路后发现这两种判断都可以。所以可以在更新了出现次数后直接判断是否大于半数,大于就直接输出,结束程序。 - 其实不用判断像素是否已经在
mp
中。map
代表的是一种映射关系,但实则此题中存储的就是两个int
值,而在int
值在这里貌似默认初始值为0
。但这么写有风险,还是做判断叭。
/*map的使用太生疏了!!!
find() 迭代器 ......
练练练!!!
*/
#include <cstdio>
#include <map>
using namespace std;
int n,m;
map<int,int> mp; // <像素点,数量>
int main()
{
scanf("%d %d",&m,&n);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
int tmp;
scanf("%d",&tmp);
map<int,int>::iterator it=mp.find(tmp);
if(it==mp.end())
mp[tmp]=1;
else
it->second=it->second+1; //mp[tmp]+=1;
}
}
int max=0,ans=0;
for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++)
{
if(it->second>max)
{
max=it->second;
ans=it->first;
}
}
printf("%d",ans);
return 0;
}
【例】A1071 Speech Patterns (25 分)
preference n. 偏爱,倾向;优先权
synonym n. 同义词;同义字
cop n. 警察
narrow down 缩小;限制;减少;变窄
validate vt. 证实,验证;确认;使生效
avatar n.化身(印度教和佛教中化作人形或兽形的神); (尤指电脑游戏或聊天室中代表使用者的)化身
alphanumerical adj. 字母数字混合编制的
lexicographically 字典序
ATTENTION
- 不是难题,单纯考STL运用。
- 注意大小写转换
- 注意
cur
的clear
map
和set
还不够熟练。本来想用set
的,因为不用自己排序了,结果不会用= =。后来发现还是用map
方便,毕竟map
可以把string
和cnt
映射起来。
#include <iostream>
#include <map>
#include <string>
using namespace std;
string str;
map<string,int> st;
int main()
{
getline(cin,str);
int idx=0;
string cur="";
while(idx<str.size())
{
if(str[idx]>='A'&&str[idx]<='Z')
str[idx]=str[idx]-'A'+'a';
while(str[idx]>='0'&&str[idx]<='9'||str[idx]>='a'&&str[idx]<='z')
{
cur+=str[idx]; //string+char?
idx++;
if(str[idx]>='A'&&str[idx]<='Z')
str[idx]=str[idx]-'A'+'a';
}
if(st.find(cur)==st.end())
st[cur]=1;
else
st[cur]++;
cur=""; //注意这里要clear
if(!(str[idx]>='0'&&str[idx]<='9'||str[idx]>='a'&&str[idx]<='z'))
{
while((!(str[idx]>='0'&&str[idx]<='9'||str[idx]>='a'&&str[idx]<='z'))&&idx<str.size())
{
idx++;
if(str[idx]>='A'&&str[idx]<='Z')
str[idx]=str[idx]-'A'+'a';
}
}
}
int cnt=0;string ans;
for(map<string,int>::iterator it=st.begin();it!=st.end();it++)
{
if(it->second>cnt)
{
cnt=it->second;
ans=it->first;
}
else if(it->second==cnt)
{
if(it->first<ans)
ans=it->first;
}
}
cout<<ans<<" "<<cnt;
return 0;
}
【例】A1149 Dangerous Goods Packaging (25 分)
incompatible adj. 不相容的;矛盾的;不能同时成立的
ATTENTION
map<int,vector<int> > mp
- 主要是不熟练这个用法,写这道题的时候都没想起来,绕了个弯子。
- 说来也难受,和平常单纯刷题比起来,模拟的时候真的会出现各种奇奇怪怪的错误…
原来版本:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> p[100010];
int m,n,k;
int goods[100010]={0};
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
int a,b;
cin>>a>>b;
p[a].push_back(b);
p[b].push_back(a);
}
for(int i=0;i<m;i++)
{
cin>>k;
fill(goods,goods+100010,0);
bool flag=true;
for(int j=0;j<k;j++)
{
int a;
cin>>a;
if(goods[a]==0)
{
goods[a]=1;
for(vector<int>::iterator it=p[a].begin();it!=p[a].end();it++)
{
goods[*it]=1;
}
}
else
{
flag=false;
//break; //不能break,会导致数还没读完就退出
}
}
if(flag) cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}
后来版本:
#include <iostream>
#include <map>
#include <vector>
using namespace std;
int n,m,k;
map<int,vector<int> > mp;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
int a,b;
cin>>a>>b;
mp[a].push_back(b);
mp[b].push_back(a);
}
while(m--)
{
bool flag=true;
int vis[100010]={0};
cin>>k;
for(int i=0;i<k;i++)
{
int p;
cin>>p;
vis[p]=1;
for(int j=0;j<mp[p].size();j++)
{
if(vis[mp[p][j]]==1)
{
flag=false;
break;
}
}
}
if(flag) cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}