C++ map容器 学习笔记

此篇为转载内容,对原作者表示感谢!


map映照容器的元素数据是一个由键值和一个映照数据组成的,键值与映照数据之间具有一一映照的关系。
map映照容器的数据结构也是采用红黑树来实现的,插入元素的键值不允许重复,比较函数只对元素的键值进行比较,元素的各项数据可通过键值检索出来,由于map与set采用的都是红黑树的数据结构,所以,用法基本相似,下图是map映照容器元素的数据构成示意图;
 
键值 映照数据    
Name Score    
Jack 98.5    
Bomi 96.0    
Kate 97.5   

使用map容器需要头文件包含语句#include <map>,map文件也包含了对multimap多重映照容器的定义;

map创建,元素插入和遍历访问


创建map对象,键值与映照数据的类型由自己定义,在没有指定比较函数时,元素的插入位置是按键值由小到大插入到黑白树中去的,这点和set一样;
下例程序详细说明了如何操作map容器:


运行结果为:
Bomi : 96.0
Jack : 98.5
Kate : 97.5

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

int main(int argc, char *argv[])
{
    //定义map对象,当前没有任何元素
    map <string, float> mp;
    mp["Jack"] = 98.5;
    mp["Bomi"] = 96.0;
    mp["Kate"] = 97.5;
    //前向遍历元素;
    map <string, float> :: iterator it;  //定义前向迭代器;
    for(it=mp.begin(); it != mp.end(); it++) {
        //输出键值与映照数据;
        cout << (*it).first << " : " << (*it).second << endl;
    }
    return 0;
}


map元素的删除

与set容器一样,map映照容器的erase()删除元素函数,可以死删除某个迭代器位置上的元素,等于某个键值的元素,一个迭代器区间上的所有元素,当然也可使用clear()的方法清空map映照容器;
下例程序演示了删除map容器中键值为28的元素:


运行结果为:
7 : t
10 : x
25 : m
30 : a

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

int main(int argc, char *argv[])
{
    //定义map对象,当前没有任何元素
    map <int, char> mp;
    //插入元素,按键值的由小到大放入黑白树中;
    mp[25] = 'm';
    mp[10] = 'x';
    mp[28] = 'k';
    mp[30] = 'a';
    mp[7] = 't';
    //删除键值为28的元素;
    mp.erase(28);
    //前向遍历元素;
    map <int, char> :: iterator it;  //定义前向迭代器;
    for(it=mp.begin(); it != mp.end(); it++) {
        //输出键值与映照数据;
        cout << (*it).first << ":" << (*it).second << endl;
    }
    return 0;
}


map元素的反向遍历

可以使用反向迭代器reverse_iterator反向遍历map映照容器中的数据,他需要rbegin()方法和rend()方法指出反向遍历的起始位置和终止位置;
下例程序详细说明了map容器反向遍历的方法:

运行结果为:
30:a
28:k
25:m
10:x
7:t

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

int main(int argc, char *argv[])
{
    //定义map对象,当前没有任何元素
    map <int, char> mp;
    //插入元素,按键值的由小到大放入黑白树中;
    mp[25] = 'm';
    mp[10] = 'x';
    mp[28] = 'k';
    mp[30] = 'a';
    mp[7] = 't';
    //反向遍历元素;
    map <int, char> :: reverse_iterator rit;  //定义反向迭代器;
    for(rit=mp.rbegin(); rit != mp.rend(); rit++) {
        //输出键值与映照数据;
        cout << (*rit).first << ":" << (*rit).second << endl;
    }
    return 0;
}


map元素的搜索

使用find()方法来搜索某个键值,如果搜索到了,则返回该键值锁在的迭代器位置,否则,返回end()迭代器的位置,由于map采用黑白树数据结构来实现,所以搜索速度是极快的;
下例程序搜索键值为28的元素:

运行结果为:
28 : 'k'

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

int main(int argc, char *argv[])
{
    //定义map对象,当前没有任何元素
    map <int, char> mp;
    //插入元素,按键值的由小到大放入黑白树中;
    mp[25] = 'm';
    mp[10] = 'x';
    mp[28] = 'k';
    mp[30] = 'a';
    mp[7] = 't';
    //前向遍历元素;
    map <int, char> :: iterator it;  //定义前向迭代器;
    //查找键值为28的元素;
    it = mp.find(28);
    if(it != mp.end()) {   //找到
        cout << (*it).first << " : " << (*it).second << endl;
    }else {   //没找到
        cout << "Not find it!" << endl;
    }
    return 0;
}

map 自定义比较函数

将元素插入到map中去的时候,map会根据设定的比较函数将该元素放到该放的节点上去,在定义map的时候,如果没有指定比较函数,那么就采用默认的比较函数,即按键值由小到大的顺序插入元素,在很多情况下,需要自己编写比较函数。
编写比较函数与set比较函数是一致的,因为它们的内部数据都是红黑树,编写方法有两种;
1>. 如果元素不是结构体,那么,可以编写比较函数,下例程序编写的比较规则是要求按键值有大到小的顺序将元素插入到map中:

运行结果为:
30:a
28:k
25:m
10:x
7:t

The Code Follows:

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

struct mycmp
{
    bool operator () (const int &a, const int &b)
    {
        return a > b;
    }
};

int main(int argc, char *argv[])
{
    //定义map对象,当前没有任何元素
    map <int, char, mycmp> mp;
    //插入元素,按键值的由小到大放入黑白树中;
    mp[25] = 'm';
    mp[10] = 'x';
    mp[28] = 'k';
    mp[30] = 'a';
    mp[7] = 't';
    map <int, char, mycmp> :: iterator it;  //定义前向迭代器中序遍历map;
    for(it=mp.begin(); it != mp.end(); it++) {
        //输出键值与映照数据;
        cout << (*it).first << ":" << (*it).second << endl;
    }
    return 0;
}


2>. 如果元素是结构体,那么可以直接把比较函数写在结构体内,下例程序详细说明了操作方法:

运行结果:
10 : Bomi 80
30 : Peti 66.5
25 : Jack 60

The Code Follows:

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

struct Info
{
    string name;
    float score;
    //重载“<”操作符,自定义排序规则;
    bool operator < (const Info &a) const
    {
        //按score从大到小排列,如果要从小到大排列,使用“>”即可;
        return a.score < score;
    }
};

int main(int argc, char *argv[])
{
    //定义map对象,当前没有任何元素;
    map <Info, int> mp;
    Info info;   //定义Info结构体变量;
    //插入元素,按键值的由小到大放入黑白树中;
    info.name = "Jack";
    info.score = 60;
    mp[info] = 25;
    info.name = "Bomi";
    info.score = 80;
    mp[info] = 10;
    info.name = "Peti";
    info.score = 66.5;
    mp[info] = 30;
    //使用前向迭代器中序遍历map;
    map <Info, int>:: iterator it;
    for(it=mp.begin(); it != mp.end(); it++) {
        cout << (*it).second << " : ";
        cout << ((*it).first).name << " " << ((*it).first).score << endl;
    }
    return 0;
}



我的总结:

map就是一个数组,只不过这个数组的下标可以是任意类型,下标的大小规则也可以自己定义,从前向后遍历和从后向前遍历需要定义不同的迭代器,可以实现O(logn)时间复杂度内查找某个下标的数据。

还有,(*it).first和(*it).second也可以写成it->first和it->second。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章