c++基础:8.2.4 _STL容器-map

孤者浪人 提交于 2020-03-04 06:40:50

1. 简介

mapkey-value构成的集合。

(***)2. 操作

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

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

map内部结构

map使用pair<key,value>类模板保存key与value,pair<key,value>有两个public成员变量:firstsecond,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;
    }

(完整代码见001_map.cpp)

#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.修改:通过修改值来修改键值对

(完整代码002_map_func.cpp)

#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)数字和出现的次数

(https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/)
在这里插入图片描述

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);
    }
}

(完整代码见003_nums_count.cpp)

#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)数字出现的次数

https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof/
在这里插入图片描述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;
}

(完整代码见004_(35-2).cpp)

 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>。对于已存在的keyinsert()操作是无法插入数据,可以通过判断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. 下标运算符[]
m[key];

如果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升序排列。自定义排序是,可以在实例化加上keycomp仿函数,重载<运算符。

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;
    });

2.把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互换
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!