• STL学习笔记 map


    STL学习笔记-- map

    map映照容器

        map映照容器所处理的元素数据,与数据库表的具有键值的记录非常相似,由一个键值和其他若干数据(映照数组)组成,键值和映照数据之间,可建立一个数学上的映照关系,由此而得映照容器的名称。容器的数据结构同样是采用红黑树进行管理,插入的元素键值不允许重复,所使用的节点元素的比较函数,只对元素的键值进行比较,元素的各项数据可通过键值检索出来。
        map 映照容器是一种关联容器,实现了 Sorted Associative Container 、Sorted Associative Container 、 Unique Associative Container 概念的接口规范
        map 容易的 C++ 标准头文件为 map ,先要用宏语句 "#include <map>" ,将红黑树和 map 的头文件包含进来,才可对使用 map 的程序进行编译
        
        
    创建 map 对象
    为了操作 map 的数据,先要用 map 的构造函数,创建一个 map 对象。
    1.    map()
        利用默认的 less<T> 函数对象和内存分配器,创建一个没有任何数元素的 map 对象。
        例如,下面的代码创建了一个空的 map 对象 m ,元素的键值类型为 char ,元素的映照数据类型为 int ,键值的比较函数对象为  greater<char>
        map<char, int, greater<char> >  m;  // 两个 ">" 、">" 符号不要写在一起了,记得要空格

    2.    map(const key_compare& comp)
        指定一个比较函数对象 comp 来创建 map 对象,内存分配器为默认值。
        map<T1,T2,less<T1> >  mapA;  //该容器是按键的升序方式排列元素。未指定函数对象,默认采用less<T1>函数对象。
        map<T1,T2,greater<T1>> mapB;   //该容器是按键的降序方式排列元素。
        less<T1>与greater<T1>  可以替换成其它的函数对象functor。
        可编写自定义函数对象以进行自定义类型的比较,使用方法与set构造时所用的函数对象一样。
        例如,下面的代码使用自定义的函数对象 strLess ,创建一个 map 容器对象 m 。该容器的键值类型为 const char* ,映照容器数据类型为 int 。
        // 定义字符串比较函数对象 strLess
        struct  strLess
        {
            bool operator() (const char* s1, const char* s2) const
            {
                return strcmp(s1, s2) < 0 ;
            }
        };
        // 创建 map 容器对象 m
        map<const char*, int >   m(strLess());
        
        
        
    3.    map(const map&)
        拷贝构造函数,用一个 map 容器的元素和比较函数,拷贝生成一个新的 map 容器对象。
        例如,下面代码利用 map 容器对象 m1 ,创建另一个容器对象 m2 .
        // map <int , char*>  m1;
        map<int, char*>  m2(m1);  // 使用默认的键值比较函数 less<int>

    4.    map(InputIterator first, InputIterator last)
        用迭代器区间 [first, last) 所指的数据,作为 map 容器的元素(包括键值和映照数据),创建一个 map 容器对象。
        例如,下面代码使用数组 pairArray 的 5 个 pair 对象,创建 map 容器对象 m 。
        pair<const int, char>  p1(1, 'a');
        pair<const int, char>  p1(2, 'b');
        pair<const int, char>  p1(3, 'c');
        pair<const int, char>  p1(4, 'd');
        pair<const int, char>  p1(5, 'e');
        pair<const int, char>  pairArray[] = {p1, p2, p3, p4, p5};
        // 创建 map 容器对象 m
        map<const int, char>  m(pairArray, pairArray + 5);
        
    5.    map(InputIterator first, InputIterator last, const key_compare& comp)    
        用迭代器区间 [first, last)所指的数据和 comp 函数对象,创建一个 map 对象。
        例如,下面代码使用 greater<int> 函数对象,取代默认的 less<int> ,创建一个 map 对象 m 。
        map<const int, char, greater<const int> >   m(pairArray, pairArray+5, greater<const int>());




    元素的插入    
        map 容器对象创建出来后,下一步就是元素数据(包括键值和映照数据)的二叉树装入。
        除可使用如下的 insert 函数,将整个元素数据进行性插入外,常用 map 容器的数组操作 "[]" ,显示地为不同键值赋予内容(映照数据),不过这个数组方法,不能检测是否插入 成功。

        假设  map<int, string> mapStu;
        
    1.    通过pair的方式插入对象         //往容器插入元素,返回pair<iterator,bool>
        pair<iteraotr, bool>  insert(const value_type& v)
        将元素 v(包括键值和映照数据)插入 map 容器,重复的 V 值不被插入。返回一个 pair 配对对象。提供所插入元素的迭代器位置和 true/false 插入成功标志
        例如,下面代码是 pair 方式的插入
        mapStu.insert(  pair<int,string>(3,"小张")  );

    2.    通过value_type的方式插入对象
        mapStu.insert(  map<int,string>::value_type(1,"小李")  );

    3.    通过数组的方式插入值
        mapStu[3] = “小刘";
        mapStu[5] = “小王";
    ......

        第三种方法非常直观,但存在一个性能的问题。插入3时,先在mapStu中查找主键为3的项,若没发现,则将一个键为3,值为初始化值的对组插入到mapStu中,然后再将值修改成“小刘”。若发现已存在3这个键,则修改这个键对应的value。
        string strName = mapStu[2];   //取操作或插入操作
        只有当mapStu存在2这个键时才是正确的取操作,【否则会自动插入一个实例,键为2,值为初始化值】。

        前两种方法,采用的是insert()方法,该方法返回值为pair<iterator,bool>
        pair< map<int,string>::iterator, bool>   pairResult = mapStu.insert(  pair<int,string>(3,"小张")  );
        如果插入成功,(pairResult.first)->first==3, (pairResult.first)->second=="小张"  pairResult.second==true。

    map 容器的元素插入
     1 #pragma warning(disable:4786)
     2 #include <map>
     3 #include <iostream>
     4 using namespace std;
     5 int main()
     6 {
     7     // 创建 map 容器对象 m
     8     map<const char*, float>  m;
     9     // 插入元素(水果名,单价),水果名位键值,单价为映照数据
    10     m["apple"] = 3.6f;
    11     m["orange"] = 3.2f;
    12     m["banana"] = 1.8f;
    13     m["pear"] = 2.3f;
    14     m["lichee"] = 6.3f;
    15     m.insert(pair<const char*, float>("何亮",100.001f) );
    16     // 打印元素
    17     cout << "苹果价格:" << m["apple"] << "元/斤 \n"; 
    18     cout << "桔子价格:" << m["orange"] << "元/斤 \n"; 
    19     cout << "香蕉价格:" << m["banana"] << "元/斤 \n"; 
    20     cout << "雪梨价格:" << m["pear"] << "元/斤 \n"; 
    21     cout << "荔枝价格:" << m["lichee"] << "元/斤 \n"; 
    22     cout << "pair插入  " << m["何亮"] << "元/斤\n";
    23 
    24     return 0;
    25 }
    复制代码
     1 #pragma warning(disable:4786)
     2 #include <map>
     3 #include <iostream>
     4 using namespace std;
     5 int main()
     6 {
     7     // 创建 map 容器对象 m
     8     map<const char*, float>  m;
     9     // 插入元素(水果名,单价),水果名位键值,单价为映照数据
    10     m["apple"] = 3.6f;
    11     m["orange"] = 3.2f;
    12     m["banana"] = 1.8f;
    13     m["pear"] = 2.3f;
    14     m["lichee"] = 6.3f;
    15     m.insert(pair<const char*, float>("何亮",100.001f) );
    16     // 打印元素
    17     cout << "苹果价格:" << m["apple"] << "元/斤 \n"; 
    18     cout << "桔子价格:" << m["orange"] << "元/斤 \n"; 
    19     cout << "香蕉价格:" << m["banana"] << "元/斤 \n"; 
    20     cout << "雪梨价格:" << m["pear"] << "元/斤 \n"; 
    21     cout << "荔枝价格:" << m["lichee"] << "元/斤 \n"; 
    22     cout << "pair插入  " << m["何亮"] << "元/斤\n";
    23 
    24     return 0;
    25 }
    复制代码
    复制代码
    元素的删除
        与 set 集合容器一样,map 映照容器的删除函数,可删除某个迭代器位置上的元素、等于某键值的元素、一个迭代器区间上的元素和容器中的所有元素。
    1.    void  erase(iterator position)    删除 position 所指的元素
    2.    size_type  erase(const key_type& k)    删除键值为 K 的元素。对 map 容器来说,此函数总是返回值 1,因为 map 容器不会出现键值重复的元素值。
    3.    void  erase(iterator first, iterator last)    删除 map 迭代器区间 [first, last) 上的所有元素
    4.    void clear()     删除 map 容器的所有元素
        例如,下面的代码将上一例子 map 对象 m 中,"lichee, 6.3" 的元素数据删除
        m.erase("lichee");
    复制代码
    遍历 map 容器元素
    1     
     2 /*    除了利用键值的数组方式来访问元素外,更一般可使用 map 容器的迭代器进行访问,通常需要用 begin 和 end 函数找出遍历开始的首元素和结束元素,然后通过迭代器的“++” 和“*” 操作,读取容器元素。
     3 
     4     下面的示例程序,将一批学生记录(学号为键值)插入到 map 容器对象 m 中,然后,利用前向迭代器打印出来。由于 map 容器的元素是通过转换为 pair 对象插入到容器的,因此,学生记录结构体中各个变量域,需要通过 pair 对象的 first 和 second 变量 指出来。(关于 pair ,可参考之前的讨论 set 容器的文章)
     5 */    
     6 
     7 -------------------------------------------------------- 遍历 map 容器元素
     8 #pragma warning(disable:4786)
     9 #include <map>
    10 #include <iostream>
    11 using namespace std;
    12 
    13 // 学生信息结构体
    14 struct StudentInfo
    15 {
    16     char* name;
    17     int year;
    18     char* addr;
    19 };
    20 
    21 // 学生记录结构体
    22 struct StudentRecord  
    23 {
    24     int id;  // 学号,作键值
    25     StudentInfo sf;  // 学生信息,作映照数据
    26 };
    27 
    28 int main()
    29 {
    30     // 3个学生的记录
    31     StudentRecord srArray[] = {
    32         {1, "何亮",21,"武汉"},
    33         {2, "何小亮",20,"上海"},
    34         {3, "何大亮",22,"北京"}
    35     };
    36     // 创建 map 容器对象 m ,管理学生记录
    37     map<int, StudentInfo> m;
    38     // 装入 3 笔学生记录
    39     for (int j=0; j<3; j++)
    40         m[srArray[j].id] = srArray[j].sf;
    41     // 迭代器遍历元素
    42     map<int, StudentInfo>::iterator i, iend;
    43     iend = m.end();
    44     cout << "学号    " << "姓名    " << "年龄    " << "地址    " << endl;
    45     for (i=m.begin(); i!=iend; ++i)
    46         cout << (*i).first << '    ' << (*i).second.name << '    ' << (*i).second.year << '    ' << (*i).second.addr << endl;
    47     cout << endl;
    48 
    49     return 0;
    50 }
    复制代码
     1     
     2 /*    除了利用键值的数组方式来访问元素外,更一般可使用 map 容器的迭代器进行访问,通常需要用 begin 和 end 函数找出遍历开始的首元素和结束元素,然后通过迭代器的“++” 和“*” 操作,读取容器元素。
     3 
     4     下面的示例程序,将一批学生记录(学号为键值)插入到 map 容器对象 m 中,然后,利用前向迭代器打印出来。由于 map 容器的元素是通过转换为 pair 对象插入到容器的,因此,学生记录结构体中各个变量域,需要通过 pair 对象的 first 和 second 变量 指出来。(关于 pair ,可参考之前的讨论 set 容器的文章)
     5 */    
     6 
     7 -------------------------------------------------------- 遍历 map 容器元素
     8 #pragma warning(disable:4786)
     9 #include <map>
    10 #include <iostream>
    11 using namespace std;
    12 
    13 // 学生信息结构体
    14 struct StudentInfo
    15 {
    16     char* name;
    17     int year;
    18     char* addr;
    19 };
    20 
    21 // 学生记录结构体
    22 struct StudentRecord  
    23 {
    24     int id;  // 学号,作键值
    25     StudentInfo sf;  // 学生信息,作映照数据
    26 };
    27 
    28 int main()
    29 {
    30     // 3个学生的记录
    31     StudentRecord srArray[] = {
    32         {1, "何亮",21,"武汉"},
    33         {2, "何小亮",20,"上海"},
    34         {3, "何大亮",22,"北京"}
    35     };
    36     // 创建 map 容器对象 m ,管理学生记录
    37     map<int, StudentInfo> m;
    38     // 装入 3 笔学生记录
    39     for (int j=0; j<3; j++)
    40         m[srArray[j].id] = srArray[j].sf;
    41     // 迭代器遍历元素
    42     map<int, StudentInfo>::iterator i, iend;
    43     iend = m.end();
    44     cout << "学号    " << "姓名    " << "年龄    " << "地址    " << endl;
    45     for (i=m.begin(); i!=iend; ++i)
    46         cout << (*i).first << '    ' << (*i).second.name << '    ' << (*i).second.year << '    ' << (*i).second.addr << endl;
    47     cout << endl;
    48 
    49     return 0;
    50 }
    复制代码
     map 容器元素的搜索
     1 /*    利用 map 容器提供的 find 函数,可搜索出具有某一键值的元素。map 容器的元素键值是唯一的。find 函数返回的迭代器值为搜索到的元素位置,如果该元素不存在,则返回一个 end 结束元素位置。
      2 
      3     下面的示例程序重写了 StudentRecord 结构体,以适于使用返回 pair 对象的 insert 函数将学生记录插入到 map 容器。 返回的 pair 对象的第二变量 second 中,判断是否插入成功(键值重复插入将失败)。然后,调用 find 函数,对学号为 2 的键值进行搜索,并将该学生的记录打印出来。
      4 */
      5 -------------------------------------------------------- map 容器元素的搜索
      6 #pragma warning(disable:4786)
      7 #include <map>
      8 #include <iostream>
      9 using namespace std;
     10 // 学生记录结构体
     11 struct StudentRecord
     12 {
     13     struct StudentInfo
     14     {
     15         char* name;
     16         int year;
     17         char* addr;
     18     };
     19     StudentRecord(int id_, char* name_, int year_, char* addr_)
     20     {
     21         id = id_;
     22         sf.name = name_;
     23         sf.year = year_;
     24         sf.addr = addr_;
     25     }
     26     int id;   // 学号,作键值
     27     StudentInfo sf;  // 其他信息
     28 };
     29 
     30 int main()
     31 {
     32     // 创建 map 容器对象 m
     33     typedef map<int, StudentRecord::StudentInfo>  studentmap;
     34     studentmap m;
     35     pair<studentmap::iterator, bool>  p;
     36 
     37     // 插入第一条学生记录
     38     StudentRecord student1 = StudentRecord(1, "何亮1号", 21, "武汉");
     39     pair<int, StudentRecord::StudentInfo>  pairStudent1(student1.id, student1.sf);
     40     p = m.insert(pairStudent1);
     41     if (!p.second)
     42         cout << "插入学生记录失败:\n" 
     43         << student1.id << '    ' 
     44         << student1.sf.name << '    '
     45         << student1.sf.year << '    '
     46         << student1.sf.addr << '    '
     47         << endl << endl;
     48 
     49     // 插入第二条学生记录
     50     StudentRecord student2 = StudentRecord(2, "何亮2号", 22, "北京");
     51     pair<int, StudentRecord::StudentInfo>  pairStudent2(student2.id, student2.sf);
     52     p = m.insert(pairStudent2);
     53     if (!p.second)
     54         cout << "插入学生记录失败:\n" 
     55         << student2.id << '    ' 
     56         << student2.sf.name << '    '
     57         << student2.sf.year << '    '
     58         << student2.sf.addr << '    '
     59         << endl << endl;
     60 
     61     // 插入第三条学生记录
     62     StudentRecord student3 = StudentRecord(3, "何亮3号", 23, "上海");
     63     pair<int, StudentRecord::StudentInfo>  pairStudent3(student3.id, student3.sf);
     64     p = m.insert(pairStudent3);
     65     if (!p.second)
     66         cout << "插入学生记录失败:\n" 
     67         << student3.id << '    ' 
     68         << student3.sf.name << '    '
     69         << student3.sf.year << '    '
     70         << student3.sf.addr << '    '
     71         << endl << endl;
     72 
     73     // 插入键值重复的学生记录, 插入失败 
     74     StudentRecord student4 = StudentRecord(3, "何亮4号", 24, "广州");
     75     pair<int, StudentRecord::StudentInfo>  pairStudent4(student4.id, student4.sf);
     76     p = m.insert(pairStudent4);
     77     if (!p.second)
     78         cout << "插入学生记录失败:\n" 
     79         << student4.id << '    ' 
     80         << student4.sf.name << '    '
     81         << student4.sf.year << '    '
     82         << student4.sf.addr << '    '
     83         << endl << endl;
     84 
     85     // 记录搜索
     86     studentmap::iterator  i = m.find(2);
     87     cout << "搜索出学号为2的记录:\n"
     88         << (*i).first << '    '
     89         << (*i).second.name << '    '
     90         << (*i).second.year << '    '
     91         << (*i).second.addr << '    '
     92         << endl << endl;
     93 
     94     // 统计 map 容器 m 所有学生的个数
     95     if (m.empty())
     96         cout << "map 容器为空" << endl;
     97     else
     98         cout << "map 容器元素个数为:" << m.size() << endl << endl;
     99 
    100     return 0;
    101 }
    复制代码
      1 /*    利用 map 容器提供的 find 函数,可搜索出具有某一键值的元素。map 容器的元素键值是唯一的。find 函数返回的迭代器值为搜索到的元素位置,如果该元素不存在,则返回一个 end 结束元素位置。
      2 
      3     下面的示例程序重写了 StudentRecord 结构体,以适于使用返回 pair 对象的 insert 函数将学生记录插入到 map 容器。 返回的 pair 对象的第二变量 second 中,判断是否插入成功(键值重复插入将失败)。然后,调用 find 函数,对学号为 2 的键值进行搜索,并将该学生的记录打印出来。
      4 */
      5 -------------------------------------------------------- map 容器元素的搜索
      6 #pragma warning(disable:4786)
      7 #include <map>
      8 #include <iostream>
      9 using namespace std;
     10 // 学生记录结构体
     11 struct StudentRecord
     12 {
     13     struct StudentInfo
     14     {
     15         char* name;
     16         int year;
     17         char* addr;
     18     };
     19     StudentRecord(int id_, char* name_, int year_, char* addr_)
     20     {
     21         id = id_;
     22         sf.name = name_;
     23         sf.year = year_;
     24         sf.addr = addr_;
     25     }
     26     int id;   // 学号,作键值
     27     StudentInfo sf;  // 其他信息
     28 };
     29 
     30 int main()
     31 {
     32     // 创建 map 容器对象 m
     33     typedef map<int, StudentRecord::StudentInfo>  studentmap;
     34     studentmap m;
     35     pair<studentmap::iterator, bool>  p;
     36 
     37     // 插入第一条学生记录
     38     StudentRecord student1 = StudentRecord(1, "何亮1号", 21, "武汉");
     39     pair<int, StudentRecord::StudentInfo>  pairStudent1(student1.id, student1.sf);
     40     p = m.insert(pairStudent1);
     41     if (!p.second)
     42         cout << "插入学生记录失败:\n" 
     43         << student1.id << '    ' 
     44         << student1.sf.name << '    '
     45         << student1.sf.year << '    '
     46         << student1.sf.addr << '    '
     47         << endl << endl;
     48 
     49     // 插入第二条学生记录
     50     StudentRecord student2 = StudentRecord(2, "何亮2号", 22, "北京");
     51     pair<int, StudentRecord::StudentInfo>  pairStudent2(student2.id, student2.sf);
     52     p = m.insert(pairStudent2);
     53     if (!p.second)
     54         cout << "插入学生记录失败:\n" 
     55         << student2.id << '    ' 
     56         << student2.sf.name << '    '
     57         << student2.sf.year << '    '
     58         << student2.sf.addr << '    '
     59         << endl << endl;
     60 
     61     // 插入第三条学生记录
     62     StudentRecord student3 = StudentRecord(3, "何亮3号", 23, "上海");
     63     pair<int, StudentRecord::StudentInfo>  pairStudent3(student3.id, student3.sf);
     64     p = m.insert(pairStudent3);
     65     if (!p.second)
     66         cout << "插入学生记录失败:\n" 
     67         << student3.id << '    ' 
     68         << student3.sf.name << '    '
     69         << student3.sf.year << '    '
     70         << student3.sf.addr << '    '
     71         << endl << endl;
     72 
     73     // 插入键值重复的学生记录, 插入失败 
     74     StudentRecord student4 = StudentRecord(3, "何亮4号", 24, "广州");
     75     pair<int, StudentRecord::StudentInfo>  pairStudent4(student4.id, student4.sf);
     76     p = m.insert(pairStudent4);
     77     if (!p.second)
     78         cout << "插入学生记录失败:\n" 
     79         << student4.id << '    ' 
     80         << student4.sf.name << '    '
     81         << student4.sf.year << '    '
     82         << student4.sf.addr << '    '
     83         << endl << endl;
     84 
     85     // 记录搜索
     86     studentmap::iterator  i = m.find(2);
     87     cout << "搜索出学号为2的记录:\n"
     88         << (*i).first << '    '
     89         << (*i).second.name << '    '
     90         << (*i).second.year << '    '
     91         << (*i).second.addr << '    '
     92         << endl << endl;
     93 
     94     // 统计 map 容器 m 所有学生的个数
     95     if (m.empty())
     96         cout << "map 容器为空" << endl;
     97     else
     98         cout << "map 容器元素个数为:" << m.size() << endl << endl;
     99 
    100     return 0;
    101 }
    复制代码


    ------------------------------- map 小结
        直观来说,map 容器区别于 set 容器的一个主要特性在于,map 是处理带有键值的记录型元素数据的快速插入、删除 和检索,而 set 则可看成是对单一数据的处理。map 将一个元素划分出键值部分,并按这个局部的键值指定整个元素的函数比较规则,来建立容器的数据分布。map 的元素键值是唯一的,不允许重复的元素键值插入。 set 和 map 都是泛型库对二叉树的一个泛化。
        
        map 缺点:map是比较高级的用法了,适合用 list , vector 就能完成的操作,就不需要用到 map 。
        map 优点:相比 set ,map 可处理带有键值的记录型数据的快速插入、删除和检索。检索的速度也是非常快的。

    ------------- 讨论到 map 这里的时候,应该说,有些地方理解起来,就有些难度了。可以网上搜一些相关的代码看看,理顺逻辑,弄清结构,孰能生巧。

    【好好学习,天天向上】 ||||||| 【 亮仔 到此一游 】
     
    标签: STLC++容器map
  • 相关阅读:
    ASP.NET 2.0 正式版中无刷新页面的开发
    Flex在线录制视频并回放(源码)
    url重写
    在Web应用程序中执行计划任务
    添加类别和修改类别(无限级别分类)
    用C#制作新闻阅读器
    字符串处理
    编程珠玑随笔
    实现元素的全排列
    提高代码质量的三要素
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3003638.html
Copyright © 2020-2023  润新知