【C++】STL:map实例分析

【1】map容器

map 是关联容器。容器中的每一个元素都是由一个键值和一个数据值组成的。

set 是一个集合它以其元素作为键值(同一个键值只能出现一次),且默认以升序排列。

list 是一个顺序容器。

【2】map容器使用方法以及实例

(1)定义、插入数据方法实例

// map容器定义、插入数据方式代码
#include<map>
#include<string>
#include<iostream>
using namespace std;

// 打印map容器数据
void print(map<int, string>& mapStu, int nValue)
{
    cout << "mapStu" << nValue << "数据信息:" << endl;
    cout << "size: " << mapStu.size() << endl;
    map<int, string>::iterator iter = mapStu.begin();
    for (; iter != mapStu.end(); ++iter)
    {
        cout << "key: " << iter->first << " value: " << iter->second << endl;
    }
    cout << endl;
}

int main()
{
    // 第一种定义map的方法
    map<int, string> mapStu1;
    // 第二种定义map的方法
    typedef map<int, string> mapType;
    mapType mapStu2, mapStu3, mapStu4;

    // 第一种插入数据方法:用insert函数插入value_type数据
    mapStu1.insert(map<int, string>::value_type(1, "Qin"));
    mapStu1.insert(map<int, string>::value_type(2, "Sun"));
    mapStu1.insert(map<int, string>::value_type(3, "Wang"));
    mapStu1.insert(map<int, string>::value_type(2, "Zhao"));
    print(mapStu1, 1);
    // 第二种插入数据方法:用insert函数插入pair数据
    mapStu2.insert(pair<int, string>(1, "Qin"));
    mapStu2.insert(pair<int, string>(2, "Sun"));
    mapStu2.insert(pair<int, string>(3, "Wang"));
    mapStu2.insert(pair<int, string>(2, "Zhao"));
    print(mapStu2, 2);
    // 第三种插入数据方法:用insert函数插入make_pair数据
    mapStu3.insert(make_pair<int, string>(1, "Qin"));
    mapStu3.insert(make_pair<int, string>(2, "Sun"));
    mapStu3.insert(make_pair<int, string>(3, "Wang"));
    mapStu3.insert(make_pair<int, string>(2, "Zhao"));
    print(mapStu3, 3);
    // 第四种插入数据方法:数组插入法
    mapStu4[1] = "Qin";
    mapStu4[2] = "Sun";
    mapStu4[3] = "Wang";
    mapStu4[2] = "Zhao";
    print(mapStu4, 4);


    pair<map<int, string>::iterator, bool> iter_pair;
    iter_pair = mapStu1.insert(map<int, string>::value_type(3, "Li"));
    //mapStu1.insert(map<int, string>::value_type(3, "Li"))返回的类型为‘std::pair<std::_Rb_tree_iterator<std::pair<const int, std::__cxx11::basic_string<char> > >, bool>’
    cout << "插入成功与否:" << iter_pair.second << endl;

    //system("pause");

    return 0;
}

// run out
/*
mapStu1数据信息:
size: 3
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang

mapStu2数据信息:
size: 3
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang

mapStu3数据信息:
size: 3
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang

mapStu4数据信息:
size: 3
key: 1 value: Qin
key: 2 value: Zhao
key: 3 value: Wang

插入成功与否:0
请按任意键继续. . .
*/

分析总结:

以上四种用法,虽然都可以实现数据的插入,但是它们是有区别的。

当然,第一、二、三种在效果上是完全一样的,用insert函数插入数据,在数据的插入过程中涉及到集合的唯一性这个概念:

即当map中有这个关键字时,insert操作再插入数据是不会成功的。

但是,用数组(第四种)方式就不同了,它可以覆盖以前该关键字对应的值,用程序说明如下:

mapStu1.insert(map<int, string>::value_type(2, "Sun"));

mapStu1.insert(map<int, string>::value_type(2, "Zhao"));

上面这两条语句执行后,mapStu1中2这个关键字对应的值是“Sun”,第二条语句并没有生效。

那么,这就涉及到我们怎么知道insert语句是否插入成功的问题?可以用pair来获得是否插入成功,程序如下:

pair<map<int, string>::iterator, bool> iter_pair;

iter_pair = mapStu1.insert(map<int, string>::value_type(3, "Li"));
//mapStu1.insert(map<int, string>::value_type(3, "Li"))返回的类型为‘std::pair<std::_Rb_tree_iterator<std::pair<const int, std::__cxx11::basic_string<char> > >, bool>’

我们通过pair的第二个变量来判断是否插入成功,它的第一个变量返回的是一个map的迭代器,

如果插入成功的话迭代器的变量iter_pair.second应该是true,否则为false。

(2)遍历map容器的三种方式

程序代码如下:

#include <map>
#include <iostream>
#include <string>
using namespace std;

// 第一种方式
void print1(map<int, string>& mapStu)
{
    cout << "第一种遍历方式:" << endl;
    cout << "size: " << mapStu.size() << endl;
    // 迭代map容器中的数据
    map<int, string>::iterator iter = mapStu.begin();
    for (; iter != mapStu.end(); ++iter)
    {
        cout << "key: " << iter->first << " value: " << iter->second << endl;
    }
    cout << endl;
}

// 第二种方式
void print2(map<int, string>& mapStu)
{
    cout << "第二种遍历方式:" << endl;
    cout << "size: " << mapStu.size() << endl;
    // 迭代map容器中的数据
    map<int, string>::reverse_iterator iter = mapStu.rbegin();
    for (; iter != mapStu.rend(); ++iter)
    {
        cout << "key: " << iter->first << " value: " << iter->second << endl;
    }

    cout << endl;
}

// 第三种方式
void print3(map<int, string>& mapStu)
{
    cout << "第三种遍历方式:" << endl;
    int nSize = mapStu.size();
    cout << "size: " << mapStu.size() << endl;
    // 迭代map容器中的数据
    for(int nIndex = 1; nIndex < nSize + 1; ++nIndex)
    {
        cout << "<" << nIndex << " :: " << mapStu[nIndex] << ">" << endl;
    }
}

int main()
{
    typedef map<int, string> mapType;
    mapType mapStu;

    // 用insert函数插入value_type数据
    mapStu.insert(map<int, string>::value_type(1, "Qin"));
    mapStu.insert(map<int, string>::value_type(2, "Sun"));
    mapStu.insert(map<int, string>::value_type(3, "Wang"));
    mapStu.insert(map<int, string>::value_type(4, "Zhao"));
    print1(mapStu);  // 第一种方式
    print2(mapStu);  // 第二种方式
    print3(mapStu);  // 第三种方式

    //system("pause");

    return 0;
}

// run out:
/*
第一种遍历方式:
size: 4
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
key: 4 value: Zhao

第二种遍历方式:
size: 4
key: 4 value: Zhao
key: 3 value: Wang
key: 2 value: Sun
key: 1 value: Qin

第三种遍历方式:
size: 4
<1 :: Qin>
<2 :: Sun>
<3 :: Wang>
<4 :: Zhao>
请按任意键继续. . .
*/

(3)查找数据的三种方式

都是已知键值查找对应的value。应用实例代码如下:

// 三种查找数据的方式
#include <map>
#include <iostream>
#include <string>
using namespace std;

// 第一种方式
void print1(map<int, string>& mapStu)
{
    cout << "遍历容器数据:" << endl;
    cout << "size: " << mapStu.size() << endl;
    // 迭代map容器中的数据
    map<int, string>::iterator iter = mapStu.begin();
    for (; iter != mapStu.end(); ++iter)
    {
        cout << "key: " << iter->first << " value: " << iter->second << endl;
    }
}

int main()
{
    typedef map<int, string> mapType;
    mapType mapStu;

    // 用insert函数插入value_type数据
    mapStu.insert(map<int, string>::value_type(1, "Qin"));
    mapStu.insert(map<int, string>::value_type(2, "Sun"));
    mapStu.insert(map<int, string>::value_type(3, "Wang"));
    mapStu.insert(map<int, string>::value_type(4, "Zhao"));
    // 第一种查找数据方式
    // count函数求的是关键字key的个数。key是不能重复的,所以返回只有0和1两种结果。
    cout << "查找关键字3的结果 : " << mapStu.count(1) << endl;
    cout << "查找关键字5的结果:  " << mapStu.count(5) << endl;
    // 第二种查找数据方式
    map<int, string>::iterator iter;
    iter = mapStu.find(1);
    if (iter != mapStu.end())
    {
        cout << "Find, the value is " << iter->second << endl;
    }
    else
    {
         cout << "Do not Find !" << endl;
    }
    // 第三种查找数据方式
    print1(mapStu);
    iter = mapStu.lower_bound(2);
    {
        cout << "lower_bound(2) :: (不小于2) " << iter->second << endl;
    }

    iter = mapStu.lower_bound(3);
    {
       cout << "lower_bound(3) :: (不小于3) " << iter->second << endl;
    }

    iter = mapStu.upper_bound(2);
    {
       cout << "upper_bound(2) :: (大于2) " << iter->second << endl;
    }

    iter = mapStu.upper_bound(3);
    {
       cout << "upper_bound(3) :: (大于3) " << iter->second << endl;
    }

    pair<map<int, string>::iterator, map<int, string>::iterator> mapPair;
    mapPair = mapStu.equal_range(2);
    if (mapPair.first == mapPair.second)
    {
        cout << "equal_range(2) :: Do not Find!" << endl;
    }
    else
    {
        cout << "equal_range(2) :: Find!" << endl;
    }

    mapPair = mapStu.equal_range(5);
    if (mapPair.first == mapPair.second)
    {
       cout << "equal_range(5) :: Do not Find!" << endl;
    }
    else
    {
        cout << "equal_range(5) :: Find!" << endl;
    }

    //system("pause");
    return 0;
}

// run out:
/*
查找关键字3的结果 : 1
查找关键字5的结果:  0
Find, the value is Qin
遍历容器数据:
size: 4
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
key: 4 value: Zhao
lower_bound(2) :: (不小于2) Sun
lower_bound(3) :: (不小于3) Wang
upper_bound(2) :: (大于2) Wang
upper_bound(3) :: (大于3) Zhao
equal_range(2) :: Find!
equal_range(5) :: Do not Find!
请按任意键继续. . .
*/

注意:

lower_bound(x)不是下界,而是大于等于x的最小值。

upper_bound(x) 大于x的最小值。

equal_range如果不明白可以查看博客https://blog.csdn.net/u013066730/article/details/84138564

(4)查询、修改、删除、大小、比较、清空、判空等等方法。

应用实例代码如下:

#include <map>
#include <string>
#include <iostream>
using namespace std;

// 打印map容器数据
void print(map<int, string>& mapStu)
{
    cout << "size: " << mapStu.size() << endl;
    // 迭代map容器中的数据
    map<int, string>::iterator iter = mapStu.begin();
    for (; iter != mapStu.end(); ++iter)
    {
        cout << "key: " << iter->first << " value: " << iter->second << endl;
    }
    cout << endl;
}

int main()
{
    typedef map<int, string> mapType;
    mapType mapStu1;

    // 用insert函数插入value_type数据
    mapStu1.insert(map<int, string>::value_type(1, "Qin"));
    mapStu1.insert(map<int, string>::value_type(2, "Sun"));
    mapStu1.insert(map<int, string>::value_type(3, "Wang"));
    mapStu1.insert(map<int, string>::value_type(2, "Zhao"));
    print(mapStu1);
    // 查找数据的两种方式:
    // 方式1:
    string str2 = mapStu1[2];
    cout << str2 << endl;
    // 方式2:
    mapType::iterator my_Iter;
    my_Iter = mapStu1.find(3);
    string str3 = my_Iter->second;
    cout << str3 << endl;
    // 修改数据的两种方式:
    // 方式1:
    mapStu1[2] = "Ma";
    // 方式2:
    my_Iter->second = "Yuan";
    print(mapStu1);
    // size 函数 和 empty函数
    cout << "size() :: " << mapStu1.size() << endl;
    cout << "empty() :: " << mapStu1.empty() << endl;
    mapStu1.clear();
    cout << "size() :: " << mapStu1.size() << endl;
    cout << "empty() :: " << mapStu1.empty() << endl;

    // 比较 ==、>=、<=、!=
    mapType mapStu2;
    cout << "mapStu1 == mapStu2 :: " << (mapStu1 == mapStu2) << endl;
    cout << "mapStu1 >= mapStu2 :: " << (mapStu1 >= mapStu2) << endl;
    cout << "mapStu1 <= mapStu2 :: " << (mapStu1 <= mapStu2) << endl;
    cout << "mapStu1 != mapStu2 :: " << (mapStu1 != mapStu2) << endl;

    mapStu1.insert(map<int, string>::value_type(1, "Qin"));
    mapStu1.insert(map<int, string>::value_type(2, "Sun"));
    mapStu1.insert(map<int, string>::value_type(3, "Wang"));
    mapStu1.insert(map<int, string>::value_type(4, "Qiang"));
    mapStu1.insert(map<int, string>::value_type(5, "Huang"));
    mapStu1.insert(map<int, string>::value_type(6, "Li"));
    mapStu1.insert(map<int, string>::value_type(7, "Hou"));
    mapStu1.insert(map<int, string>::value_type(8, "Lin"));
    mapStu1.insert(map<int, string>::value_type(9, "Li"));


    // 删除操作
    cout << "删除前打印数据信息:" << endl;
    print(mapStu1);

    mapType::iterator iter;
    // 第一种删除(代码1)
    for (iter = mapStu1.begin(); iter != mapStu1.end();)
    {
        if (5 == iter->first)
        {
            mapStu1.erase(iter++);
        }
        else
        {
            ++iter;
        }
    }

    // 第一种删除(代码2)(注意代码层面的差异)
    for (iter = mapStu1.begin(); iter != mapStu1.end();)
    {
        if ("Li" == iter->second)
        {
            mapStu1.erase(iter++);
        }
        else
        {
            ++iter;
        }
    }
    cout << "删除关键字5 以及 值“Li”后: " << endl;
    print(mapStu1);

    // 第一种删除(代码3)(注意代码层面的差异)
    my_Iter = mapStu1.find(2);
    mapStu1.erase(my_Iter);
    cout << "删除关键字2后: " << endl;
    print(mapStu1);

    // 第二种删除(直接删除关键字)
    int nResult = mapStu1.erase(3); // 如果删除了会返回1,否则返回0
    cout << nResult << endl;
    cout << "删除关键字3后: " << endl;
    print(mapStu1);

    // 第三种删除(用迭代器,成片的删除)
    mapStu1.erase(++mapStu1.begin(), mapStu1.end());
    cout << "剩第一位,其它全部删除后: " << endl;
    print(mapStu1);

    return 0;
}

// run out:
/*
size: 3
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang

Sun
Wang

size: 3
key: 1 value: Qin
key: 2 value: Ma
key: 3 value: Yuan

size() :: 3
empty() :: 0
size() :: 0
empty() :: 1
mapStu1 == mapStu2 :: 1
mapStu1 >= mapStu2 :: 1
mapStu1 <= mapStu2 :: 1
mapStu1 != mapStu2 :: 0

删除前打印数据信息:
size: 9
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
key: 4 value: Qiang
key: 5 value: Huang
key: 6 value: Li
key: 7 value: Hou
key: 8 value: Lin
key: 9 value: Li

删除关键字5 以及 值“Li”后:
size: 6
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
key: 4 value: Qiang
key: 7 value: Hou
key: 8 value: Lin

删除关键字2后:
size: 5
key: 1 value: Qin
key: 3 value: Wang
key: 4 value: Qiang
key: 7 value: Hou
key: 8 value: Lin

1
删除关键字3后:
size: 4
key: 1 value: Qin
key: 4 value: Qiang
key: 7 value: Hou
key: 8 value: Lin

剩第一位,其它全部删除后:
size: 1
key: 1 value: Qin

请按任意键继续. . .
*/

(5)map 容器排序问题

请看下面一段代码:

#include <map>
#include <string>
#include "iostream"
using namespace std;

typedef struct tagStudentInfo
{
    int nID;
    string strName;
} StudentInfo, *PStudentInfo;  // 学生信息

void main()
{
    // 用学生信息映射分数
    map<StudentInfo, int> mapStudent;
    StudentInfo studentInfo;
    studentInfo.nID = 1;
    studentInfo.strName = "student_one";
    mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90));
    studentInfo.nID = 2;
    studentInfo.strName = "student_two";
    mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80));
}

注意:以上程序编译无法通过!

由编译器错误提示分析:排序问题!STL中默认是采用小于号来排序的,当关键字是一个结构体时,涉及到排序就会出现问题。

因为它没有小于号操作,insert等函数在编译的时候过不去,下面给出两个方法解决这个问题:

1、解决方法1,重载运算符。

// 解决方法1

#include <map>
#include <string>
#include "iostream"
using namespace std;

typedef struct tagStudentInfo
{
    int nID;
    string strName;

    bool operator < (tagStudentInfo const & _A)const
    {
        // 这个函数指定排序策略,按nID排序,如果nID相等的话,按strName排序。
        if (nID < _A.nID)
            return true;
        if (nID == _A.nID)
            return strName.compare(_A.strName) < 0;

        return false;
    }
} StudentInfo, *PStudentInfo;  // 学生信息

void print(map<StudentInfo, int>& mapStu)
{
    cout << "size: " << mapStu.size() << endl;
    // 迭代map容器中的数据
    map<StudentInfo, int>::iterator iter = mapStu.begin();
    for (; iter != mapStu.end(); ++iter)
    {
        cout << "key: " << iter->first.nID << " value: " << iter->second << endl;
    }
    cout << endl;
}

int main()
{
    // 用学生信息映射分数
    map<StudentInfo, int> mapStudent;
    StudentInfo studentInfo;
    studentInfo.nID = 1;
    studentInfo.strName = "student_one";
    mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90));
    studentInfo.nID = 2;
    studentInfo.strName = "student_two";
    mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80));

    print(mapStudent);

    return 0;
}


/*
//run out:
size:2
key:1 value:90
key:2 value:80
*/

2、解决方法2,仿函数。

// 解决方法2
#include <map>
#include <string>
#include "iostream"
using namespace std;

typedef struct tagStudentInfo
{
    int nID;
    string strName;
} StudentInfo, *PStudentInfo;  // 学生信息

class sort
{
public:
    bool operator()(StudentInfo const & _A, StudentInfo const & _B) const
    {
        if (_A.nID < _B.nID)
            return true;
        if (_A.nID == _B.nID)
            return _A.strName.compare(_B.strName) < 0;

        return false;
    }
};

void print(map<StudentInfo, int, sort>& mapStu)
{
    cout << "size: " << mapStu.size() << endl;
    // 迭代map容器中的数据
    map<StudentInfo, int>::iterator iter = mapStu.begin();
    for (; iter != mapStu.end(); ++iter)
    {
        cout << "key: " << iter->first.nID << " value: " << iter->second << endl;
    }
    cout << endl;
}

int main()
{
    // 用学生信息映射分数
    map<StudentInfo, int, sort> mapStudent;
    StudentInfo studentInfo;
    studentInfo.nID = 1;
    studentInfo.strName = "student_one";
    mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90));
    studentInfo.nID = 2;
    studentInfo.strName = "student_two";
    mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80));

    print(mapStudent);

    return 0;
}


/*
//run out:
size:2
key:1 value:90
key:2 value:80
*/

6)待续...

【3】总结说明

(1)由于STL是一个统一的整体,map的很多用法都和STL中其它的东西结合在一起。

比如,在排序方面,这里默认用的是小于号,即less<>,如果要从大到小排序呢,这里涉及到的东西很多,在此无法一一加以说明。

(2)map容器内部有序,由红黑树保证,因此很多函数执行的时间复杂度都是log2N的,用map函数可以实现的功能,而STL Algorithm也可以完成该功能。

但是,建议用map自带函数,效率更高一些。

(3)map在空间上的特性。

由于map的每个数据对应红黑树上的一个节点,这个节点在不保存你的数据时,是占用16个字节:

一个父节点指针,左右两个孩子指针,还有一个枚举值(标示红黑的,相当于平衡二叉树中的平衡因子)。

猜你喜欢

转载自blog.csdn.net/u013066730/article/details/84138154