考研复试系列——第十一节 map的使用
前言
在考研上机试题中,还是经常出现一些类如词频统计的问题的,解决这类问题通常使用哈希表,在C++的STL当然提供了对其支持,比如c++中的hash_map。
在实际做题中,我们只需要使用map就OK了 。map与hashmap的用法基本一致,但底层实现是不同的,前者使用红黑树实现,后者使用哈希表实现。
当然在做题中直接map就足够了。所以这里只记录下map的使用方法。
map基础
#pragma warning(disable:4786)//消除4786警告
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main()
{
string str = "wangcan";
reverse(str);
map<string,int> mmap;
//插入数据
mmap.insert(map<string,int>::value_type("wang",10));
mmap.insert(pair<string,int>("wwww",5));
mmap.insert(make_pair<string,int>("cumt",77));
mmap["csdn"] = 3;
//查找数据
int n = mmap["csdn"];
map<string,int>::iterator iter;
iter = mmap.find("csdn");//find返回一个迭代器
int m = iter->second;//利用迭代器获取m的值
for(iter=mmap.begin();iter!=mmap.end();iter++)//利用迭代器遍历
cout<<iter->first<<":"<<iter->second<<endl;
//修改数据
mmap["csdn"] = 10;
iter = mmap.find("csdn");
iter->second = 10;
return 0;
//删除数据
mmap.erase("cumt");//根据键值删除
mmap.erase(iter);//利用迭代器删除
mmap.clear();//清空所有
}
例题一
下面来一道以前做过的ACM的map的水题 。题目描述:
程序员Astar不仅热爱编程, 也热爱运动, 最近,他所在的公司准备组织大家开展一些体育活动, 在此之前希望了解每个人所喜欢的体育运动有哪些, 担任这次活动统计的程序员Astar要求参与投票的每个人写上自己最喜爱的3项体育运动, 并在最终结果中选出3项最受欢迎的(喜爱人数最多的前3名)作为这次活动准备开展的运动, 如果前3名中出现票数相同的, 则字母序较小的优先选择。
输入:输入的第一行有一个正整数n (n <= 100), 接下来的每一行有3个不相同的非空字符串(每个字符串只由小写字母构成, 且长度都不大于10),
代表了参与投票的人喜爱的3项运动。
输出 :按字母序的先后顺序输出一行最受欢迎的前三项运动, 每两项之间由一个空格隔开。
sample input:
3
tennis basketball golf
tennis football basketball
badminton tennis chess
sample input:
3
tennis basketball golf
tennis football basketball
badminton tennis chess
sample output:
badminton basketball tennis
代码如下:
#pragma warning(disable:4786)
#include<iostream>
#include<algorithm>
#include<map>
#include<string>
using namespace std;
bool cmp(const string a,const string b)
{
return a < b;
}
int main()
{
map<string,int> mmap;
map<string,int>::iterator iter;
int m,i;
cin>>m;
string str[3];
while(m--)
{
cin>>str[0]>>str[1]>>str[2];
for(i=0;i<3;i++)
{
iter = mmap.find(str[i]);
if(iter == mmap.end())//查找不到
mmap[str[i]] = 1;
else
mmap[str[i]]++;
}
}
int value[3];
for(i=0;i<3;i++)
{
iter = mmap.begin();
str[i] = iter->first;
value[i] = iter->second;//保存最大值,其实题目并没有要求记录这个
iter++;
for(;iter!=mmap.end();iter++)
{
if(iter->second > value[i])//后者值大的话
{
str[i] = iter->first;
value[i] = iter->second;
}
else if(iter->second == value[i])//两者值相等的话
{
if(iter->first < str[i])//比较字典序
{
str[i] = iter->first;
value[i] = iter->second;
}
}
}
mmap.erase(str[i]);//删除已经找到的最大元素
}
sort(str,str+3,cmp);//按字典需排列
cout<<str[0]<<" "<<str[1]<<" "<<str[2]<<endl;
return 0;
}
是不是发现有了map解决这类问题简单了很多。
例题二
题目描述:
哈利波特在魔法学校的必修课之一就是学习魔咒。据说魔法世界有100000种不同的魔咒,哈利很难全部记住,但是为了对抗强敌,他必须在危急时刻能够调用任何一个需要的魔咒,所以他需要你的帮助。
给你一部魔咒词典。当哈利听到一个魔咒时,你的程序必须告诉他那个魔咒的功能;当哈利需要某个功能但不知道该用什么魔咒时,你的程序要替他找到相应的魔咒。如果他要的魔咒不在词典中,就输出“what?”
输入:
首先列出词典中不超过100000条不同的魔咒词条,每条格式为:
[魔咒] 对应功能
其中“魔咒”和“对应功能”分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。词典最后一行以“@END@”结束,这一行不属于词典中的词条。
词典之后的一行包含正整数N(<=1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。
输出:
每个测试用例的输出占一行,输出魔咒对应的功能,或者功能对应的魔咒。如果魔咒不在词典中,就输出“what?”
sample input:
[expelliarmus] the disarming charm
[rictusempra] send a jet of silver light to hit the enemy
[tarantallegra] control the movement of one's legs
[serpensortia] shoot a snake out of the end of one's wand
[lumos] light the wand
[obliviate] the memory charm
[expecto patronum] send a Patronus to the dementors
[accio] the summoning charm
@END@
4
[lumos]
the summoning charm
[arha]
take me to the sky
sample output:
light the wand
accio
what?
what?
哈利波特在魔法学校的必修课之一就是学习魔咒。据说魔法世界有100000种不同的魔咒,哈利很难全部记住,但是为了对抗强敌,他必须在危急时刻能够调用任何一个需要的魔咒,所以他需要你的帮助。
给你一部魔咒词典。当哈利听到一个魔咒时,你的程序必须告诉他那个魔咒的功能;当哈利需要某个功能但不知道该用什么魔咒时,你的程序要替他找到相应的魔咒。如果他要的魔咒不在词典中,就输出“what?”
输入:
首先列出词典中不超过100000条不同的魔咒词条,每条格式为:
[魔咒] 对应功能
其中“魔咒”和“对应功能”分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。词典最后一行以“@END@”结束,这一行不属于词典中的词条。
词典之后的一行包含正整数N(<=1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。
输出:
每个测试用例的输出占一行,输出魔咒对应的功能,或者功能对应的魔咒。如果魔咒不在词典中,就输出“what?”
sample input:
[expelliarmus] the disarming charm
[rictusempra] send a jet of silver light to hit the enemy
[tarantallegra] control the movement of one's legs
[serpensortia] shoot a snake out of the end of one's wand
[lumos] light the wand
[obliviate] the memory charm
[expecto patronum] send a Patronus to the dementors
[accio] the summoning charm
@END@
4
[lumos]
the summoning charm
[arha]
take me to the sky
sample output:
light the wand
accio
what?
what?
#pragma warning(disable:4786)
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{
char cstr[100];
map<string,string> mmap1;//记录魔咒-解释
map<string,string> mmap2;//记录解释-魔咒
map<string,string>::iterator iter;//迭代器
while(gets(cstr))
{
string sstr(cstr);
if(sstr == "@END@")
break;
int index = sstr.find(']');
string sstr1 = sstr.substr(0,index+1);//先记录[和]
string sstr2 = sstr.substr(index+2);//除去空格
//cout<<sstr1<<":"<<sstr2<<endl;
mmap1[sstr1] = sstr2;
mmap2[sstr2] = sstr1.substr(1,sstr1.length()-2);//解释-魔咒中魔咒不含[和]
}
int n;
cin>>n;
gets(cstr);//在cin后面跟着gets的话gets会把cin的\n识别为字符串,所以进入循环之前先输入一次(环境vc6)
while(n--)
{
gets(cstr);
string str(cstr);
if(str[0] == '[')//说明是魔法要查定义
{
iter = mmap1.find(str);
if(iter != mmap1.end())//如果找到
cout<<mmap1[str]<<endl;
else
cout<<"what?"<<endl;
}
else//说明是定义要查魔法
{
iter = mmap2.find(str);
if(iter != mmap2.end())
cout<<mmap2[str]<<endl;
else
cout<<"what?"<<endl;
}
}
return 0;
}
这里之所以没有使用getline直接读入string,是因为在我的编译环境中(vc6)发现使用getline需要两次回车才能读入一个字符串。在高版本的vs中没有这个问题。