C++基础12:STL容器map

1. 简介

map 是 key-value 构成的集合。

2. 操作

map 是键值对 <key,value> 构据集合。key 必须唯一。

  • 主要用来查找key对应value,要求key必须是可排序的,必须支持<比较运算符。
  • map默认是以key升序存放键值对<key,value>数据,比较适合二分查找。
    map内部结构

map 使用 pair<key,value> 类模板保存 key 与 value,pair<key,value> 有两个 public 成员变量: first 和 second , first 存放 key , second 存放 value。在 map 里面可以使用 map<>::value_type 表示 pair<key,value>。

typedef pair<key,value> value_type;

2.1 初始化

  1. 默认构造(可带参数)
  2. 复制构造
  3. 范围赋值构造

初始化时必须给 map<> 类模板同时设置key与value的类型模板实参。
实参类型不限于基本类型、类类型(class、struct、union),还可以是容器模板。

a.只能前面的键找后面的数值;后面的找前面的返回空字符;

cout << fruits["香蕉"] <<endl;  //a.只能前面的键找后面的数值;
cout << fruits["banana"] <<endl;  //a.后面的找前面的返回空字符;

b.找到了返回内容,找不到返回空字符;可以用if判断

   if(fruits.count("香蕉")==1){    //b.找到了返回内容,找不到返回空字符;,可以用if判断
        cout << fruits["香蕉"] <<endl;
    }
  • 完整案例
#include <iostream>
#include <map>
using namespace std;

int main()
{
    map<string,string> fruits ={
    {"香蕉","banana"},
    {"苹果","apple"},
    {"橘子","orange"}
    };
    for(auto p: fruits){  //c++11的常见用法;
        cout << p.first <<"\t" << p.second << endl;
    }

    cout << fruits["香蕉"] <<endl;  //a.只能前面的键找后面的;
    cout << fruits["banana"] <<endl;  //a.后面的找前面的返回空字符;
    if(fruits.count("香蕉")==1){    //b.找到了返回内容,找不到返回空字符;,可以用if判断
        cout << fruits["香蕉"] <<endl;
    }
    return 0;
}

2.2 修改&添加&删除&遍历常见的用法

a.遍历常见的用法

for(auto p: fruits){  //c++11的常见用法;
        cout << p.first <<"\t" << p.second << endl;
    }

b.删除:通过删除键来删除键值对

 fruits.erase("香蕉");   

c.插入:(法1)pair()通过类型插入键值对;
(法2:常用)make_pair()直接添加键值对

 fruits.insert(pair<string,string>("樱桃","cherry"));//c1.pair()通过类型插入键值对;
    fruits.insert(make_pair("梨子","pear"));//c2.make_pair()直接添加键值对

d.修改:通过修改值来修改键值对

fruits["橘子"] = "juice"; //d.修改:通过修改值来修改键值对
  • 完整案例
#include <iostream>
#include <map>
using namespace std;

int main()
{
    map<string,string> fruits ={
    {"香蕉","banana"},
    {"苹果","apple"},
    {"橘子","orange"}
    };

    fruits.erase("香蕉");   //b.删除:通过删除键来删除键值对
    for(auto p: fruits){  //a.c++11的常见遍历用法;
        cout << p.first <<"\t" << p.second << endl;
    }

    cout << endl;
	fruits["橘子"] = "juice"; //d.修改:通过修改值来修改键值对
    fruits.insert(pair<string,string>("樱桃","cherry"));//c1.pair()通过类型插入键值对;
    fruits.insert(make_pair("梨子","pear"));//c2.make_pair()直接添加键值对
    for(auto p: fruits){  //c++11的常见用法;
        cout << p.first <<"\t" << p.second << endl;
    }
    cout << endl;
    map<string,string>::iterator it = fruits.find("苹果");
    if(it != fruits.end()){
        cout << it ->first << it->second << endl;
    }
    return 0;
}

2.3 面试常考

2.3.1 (面试题56)数字和出现的次数

数字和出现的次数

在这里插入图片描述
step1. 键值对表示<数字,次数>,首先遍历向量nums,将其存入map;
空值插入1;非空的话,次数自增

map<int,int> m;      //a.键值对表示<数字,次数>
for(auto n:nums){   //b1.首先遍历向量nums,将其存入map
    if(m.count(n)==0){
        m.insert(make_pair(n,1));//b2.空值插入1
    }else{
        ++m[n];               //b3.非空的话,次数自增
    }

step2 遍历map,次数为1的将键存入到vector

for(auto p:m){               //c.遍历map,次数为1的将键存入到vector
    if(p.second == 1){
        res.push_back(p.first);
    }
}
  • 完整代码
#include <iostream>
#include <map>
#include <vector>

using namespace std;


vector<int> timesNumbers(vector<int>& nums){
map<int,int> m;      //a.键值对表示<数字,次数>
for(auto n:nums){   //b1.首先遍历向量nums,将其存入map
    if(m.count(n)==0){
        m.insert(make_pair(n,1));//b2.空值插入1
    }else{
        ++m[n];               //b3.非空的话,次数自增
    }

}

vector<int> res;
for(auto p:m){               //c.遍历map,次数为1的将键存入到vector
    if(p.second == 1){
        res.push_back(p.first);
    }
}
    return res;
}

int main()
{
    vector<int> vec = {4,1,4,6};
    vector<int> res = timesNumbers(vec);
    for(auto n:res){
    cout << n << "\t";
}
cout << endl;
return 0;
}

2.3.2 (面试题56-2)数字出现的次数

数字出现的次数
在这里插入图片描述
step1. 键值对表示<数字,次数>,首先遍历向量nums,将其存入map;
空值插入1;非空的话,次数自增

map<int,int> m;      //a.键值对表示<数字,次数>
for(auto n:nums){   //b1.首先遍历向量nums,将其存入map
    if(m.count(n)==0){
        m.insert(make_pair(n,1));//b2.空值插入1
    }else{
        ++m[n];               //b3.非空的话,次数自增
    }

step2. 遍历nums,将次数为1的键返回;

for(auto p:m){               //c.将次数为1的键返回;
    if(p.second == 1){
        res=p.first;
    }
}
    return res;
}
  • 完整代码
 int singleNumber(vector<int>& nums) {
       map<int,int> m;      //a.键值对表示<数字,次数>
for(auto n:nums){   //b1.首先遍历向量nums,将其存入map
    if(m.count(n)==0){
        m.insert(make_pair(n,1));//b2.空值插入1
    }else{
        ++m[n];               //b3.非空的话,次数自增
    }
    }

    

int res;
for(auto p:m){               //c.遍历nums,将次数为1的键返回;
    if(p.second == 1){
        res=p.first;
    }
}
    return res;
}

3.标准

  • 迭代器
迭代器作用
c.begin()头迭代器
c.end()尾迭代器
c.rbegin()反向头迭代器
c.rend()反向尾迭代器

与vector相似。

  • 数据量操作
函数作用
c.size()大小
c.max_size()最大大小
c.empty()判空
c.clear()清空

3.1 添加数据

  1. insert插入pair<>数据
 #include <iostream>
    #include <map>
    #include <algorithm>
    using namespace std;
    void Display(map<int,int>::value_type const& val){
        cout << val.first <<" " << val.second << endl;
    }
    int main(){
        map<int,int> m;
        for(int i=0;i<10;i++){
            m.insert(pair<int,int>(i,i*10));
        }
        for_each(m.begin(),m.end(),Display);
    }
  1. insert插入map<>::value_type数据
 #include <iostream>
    #include <map>
    #include <algorithm>
    using namespace std;
    void Display(map<int,int>::value_type const& val){
        cout << val.first <<" " << val.second << endl;
    }
    int main(){
        map<int,int> m;
        for(int i=0;i<10;i++){
            m.insert(map<int,int>::value_type(i,i*10));
        }
        for_each(m.begin(),m.end(),Display);
    }
  1. insert插入make_pair数据
    make_pair是一个函数模板,类似与如下实现:
  template<class K,class V)
    inline pair<K,V> make_pair(K const& k,V const& v){
        return pair<K,V>(k,v);
    }
    
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
void Display(map<int,int>::value_type const& val){
    cout << val.first <<" " << val.second << endl;
}
int main(){
    map<int,int> m;
    for(int i=0;i<10;i++){
        m.insert(make_pair(i,i*10));
    }

    for_each(m.begin(),m.end(),Display);
}
  1. 下标运算符[]添加数据
 #include <iostream>
    #include <map>
    #include <algorithm>
    using namespace std;
    void Display(map<int,int>::value_type const& val){
        cout << val.first <<" " << val.second << endl;
    }
    int main(){
        map<int,int> m;
        for(int i=0;i<10;i++){
            m[i] = i*10;
        }
        for_each(m.begin(),m.end(),Display);
    }

说明:

  • map只有在访问key,如果key不存在则会创建,反之,使用已存在的<key,val>。对于已存在的key,insert()操作是无法插入数据,可以通过判断insert()的返回值pair<map<>::iterator,bool>,得知是否插入成功。
vector为空,是否可以使用下标运算符添加数据?例如:vec[2]=3;

3.2 遍历

  • 迭代器for循环
   for(map<int,int>::iterator it = m.begin();it != m.end();it++){
            cout << "[" << it->first << "]=" << it->second() << endl; 
    }
  • for_each()循环
    定义函数指针
 inline void Display(map<int,int>::value_type const& val){
        cout << "[" << val.first << "]=" << val.second << endl;
    }

执行for_each

   for_each(m.begin(),m.end(),Display);
  • C++11auto迭代器写法
   for(auto it = m.begin();it != m.end();it++){
            cout << "[" << it->first << "]=" << it->second() << endl; 
    }
  • C++11 for-loop-scope迭代器写法
  for(auto p : m){
        cout << "[" << p.first << "]=" << p.second << endl;
    }
  • C++11 for_each()与lamdba表达式
for_each(m.begin(),m.end(),[](map<int,int>::value_type& p){
    cout << "[" << p.first << "]=" << p.second << endl;
});

3.3key查找

  1. count()判断key是否存在
   if(m.count(key) == 1){
         ...
    }
  1. find()判断key是否存在以及位置
map<int,int>::iterator it = m.find(key);
if(m.end() != it){
     ...
}
  1. 下标运算符[]
下标运算符[]

如果key不存在,默认创建。

3.4 区域查找

成员变量作用
m.lower_bound(key)key下边界
m.upper_bound(key)key上边界
m.equal_range(key)key上下边界

3.5 删除

  1. 关键字删除
   m.erase(key);
  1. 迭代器删除
   m.erase(m.begin());
  1. 区域删除
m.erase(it_a,it_b);

3.6 排序

默认按照key升序排列。自定义排序是,可以在实例化加上key的comp仿函数,重载<运算符。

map<key类型,value类型,comp> m;

4. 实例

1.两个数组合并成一个map

#include <iostream>
#include <map>
#include <iterator>
#include <algorithm>
using namespace std;
void Display(map<int,int>::value_type const& val){
    cout << "[" << val.first << "]=" << val.second << endl;
}
class MapMaker{
public:
    MapMaker(map<int,int>& m):m_(m){}
    inline bool operator()(int k,int v){
        return m_.insert(make_pair(k,v)).second;
    }
private:
    map<int,int>& m_;
};
int main(){
    map<int,int> m;
    int arr1[] = {1,2,1,4,5,2,3,4}; 
    int arr2[] = {19,29,39,49,59,69,79,89}; 
    bool res[8];
    transform(arr1,arr1+8,arr2,res,MapMaker(m));
    cout<< boolalpha;
    copy(res,res+8,ostream_iterator<bool>(cout,","));
    cout<< noboolalpha << endl;
    for_each(m.begin(),m.end(),Display);
}

在C++11中transform可以使用lamdba表达式,改写成

 transform(arr1,arr1+8,arr2,res,[&m](int k,int v){
        return m.insert(make_pair(k,v)).second;
    });
  1. 把map的key和value各自分解成一个vector
#include <iostream>
#include <algorithm>
#include <iterator> // ostream_iterator
#include <vector>
#include <map>
using namespace std;
// 仿函数
class Spliter{
public:
    Spliter(vector<int>& k,vector<int>& v):k_(k),v_(v){}
    void operator()(map<int,int>::value_type const& pair){
        k_.push_back(pair.first);
        v_.push_back(pair.second);
    }
private:
    vector<int>& k_;
    vector<int>& v_;
};
int main () {
  map<int,int> m;
  for(int i=0;i<10;i++){
    m[i] = i*10;
  }
  vector<int> keys;
  vector<int> values;
  for_each(m.begin(),m.end(),Spliter(keys,values));
  copy(keys.begin(),keys.end(),ostream_iterator<int>(cout,","));
  cout << endl;
  copy(values.begin(),values.end(),ostream_iterator<int>(cout,","));
  return 0;
}

在C++11中for_each可以使用lamdba表达式,改写成

  for_each(m.begin(),m.end(),[&keys,&values](map<int,int>::value_type const& pair){
            keys.push_back(pair.first);
            values.push_back(pair.second);
    });

使用C++11 for-loop-scope语法

   for(auto p:m){
        keys.push_back(p.first);
        values.push_back(p.second);
    }
  1. map的key和value互换
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值