STL后续-map/multimap/unordered_map容器

map容器

map容器原理图

map容器和multiset容器一样,元素都是对组pair,map容器不允许存在两个相同的键值的元素

map容器的迭代器也是只读迭代器。

map容器API

#include <iostream>
#include <map>
using namespace std;
/*
 * map构造函数
 * map<T1,T2> map1;//默认构造函数
 * map(const map &map1);//默认拷贝构造函数
 *
 * map容器赋值操作
 * map &operator=(const map &map);//重载等号运算符拷贝
 * swap(map1);//交换函数
 *
 * map容器大小操作
 * size();//返回容器元素的数目
 * empty();//判断容器是否为空
 *
 * map容器数据存取操作
 * map.insert(pair(键值,实值));//map容器元素都是对组,插入成功返回pair<iterator,bool>;
 * map<int,string> map1;
 * map1.insert(pair<int,string>(1,"张三"));
 * map1.insert(make_pair(2,"李四"));
 * map1.insert(map<int,string>::value_type(3,"张三丰"));
 * map1[4]="小王";
 * map容器的删除操作
 * map1.clear();//清空所有元素
 * erase(position);//删除position所指的元素,返回下一个元素的迭代器
 * erase(begin,end);//删除区间[begin,end)的所有元素
 * erase(keypair);//删除key为keypair的对组
 * map容器的查找操作
 * find(key);//查找key是否存在,若存在返回该key的元素的迭代器,不存在返回该容器最后一个迭代器即map1.end();
 * count(keyElement);//返回容器中key为keyElement的对组个数,注意因为map容器的特殊性,count返回的个数要么为0,要么为1
 * 而multimap则可能会返回>1
 * lower_bound(keyElement);//返回第一个key>=keyElement的元素的迭代器
 * upper_bound(keyElement);//返回第一个key>keyElement的元素的迭代器
 * equal_range(keyElement);//返回容器中key与keyElement相等的上下限的两个迭代器
 */

//自定义map容器遍历算法
void printMap1(map<int,string> &map1){
    map<int,string>::const_iterator it=map1.begin();
    for(;it!=map1.end();it++){
        //*it==pair<int,string>;注意这里的*it是map容器的元素(pair)
        cout<<(*it).first<<" "<<(*it).second<<endl;
    }
}

void test(){
    map<int,string> map1;
    map1.insert(pair<int,string>(10086,"中国移动"));
    map1.insert(make_pair(10000,"中国电信"));
    map1.insert(map<int,string>::value_type(10010,"中国联通"));
    map1[9527]="星爷";
    //注意map容器key不可以重复且要存在
    cout<<map1[1008]<<endl;
    cout<<map1.count(10086)<<endl;
    printMap1(map1);
}

int main()
{
    test();
    return 0;
}

输出结果:

通过上下文顺序和输出结果对比,发现数组形式优先遍历,之后是make_pair,map<int,string>::value_type();最后是pair<int,string>,模板的调用有先后顺序,但是数组容器发生数组下标访问越界导致程序出现异常,因此建议优先使用make_pair。

map的实值为类的应用 (less比较)

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

/*
 * map构造函数
 * map<T1,T2> map1;//默认构造函数
 * map(const map &map1);//默认拷贝构造函数
 *
 * map容器赋值操作
 * map &operator=(const map &map);//重载等号运算符拷贝
 * swap(map1);//交换函数
 *
 * map容器大小操作
 * size();//返回容器元素的数目
 * empty();//判断容器是否为空
 *
 * map容器数据存取操作
 * map.insert(pair(键值,实值));//map容器元素都是对组,插入成功返回pair<iterator,bool>;
 * map<int,string> map1;
 * map1.insert(pair<int,string>(1,"张三"));
 * map1.insert(make_pair(2,"李四"));
 * map1.insert(map<int,string>::value_type(3,"张三丰"));
 * map1[4]="小王";
 * map容器的删除操作
 * map1.clear();//清空所有元素
 * erase(position);//删除position所指的元素,返回下一个元素的迭代器
 * erase(begin,end);//删除区间[begin,end)的所有元素
 * erase(keypair);//删除key为keypair的对组
 * map容器的查找操作
 * find(key);//查找key是否存在,若存在返回该key的元素的迭代器,不存在返回该容器最后一个迭代器即map1.end();
 * count(keyElement);//返回容器中key为keyElement的对组个数,注意因为map容器的特殊性,count返回的个数要么为0,要么为1
 * 而multimap则可能会返回>1
 * lower_bound(keyElement);//返回第一个key>=keyElement的元素的迭代器
 * upper_bound(keyElement);//返回第一个key>keyElement的元素的迭代器
 * equal_range(keyElement);//返回容器中key与keyElement相等的上下限的两个迭代器
 */
//自定义map容器遍历算法
void printMap1(map<int,string> &map1){
    map<int,string>::const_iterator it=map1.begin();
    for(;it!=map1.end();it++){
        //*it==pair<int,string>;注意这里的*it是map容器的元素(pair)
        cout<<(*it).first<<" "<<(*it).second<<endl;
    }
}

class Person
{
    friend void printMap2(map<int,Person,less<int>> &map2);
public:
    Person() {}
    Person(int num,string name,double score){
        this->name=name;
        this->num=num;
        this->score=score;
    }

private:
    int num;
    string name;
    double score;
};


void printMap2(map<int,Person,less<int>> &map2){
    map<int,Person,less<int>>::const_iterator it1=map2.begin();
    for(;it1!=map2.end();it1++){
        cout<<(*it1).first<<" "<<(*it1).second.name<<" "<<(*it1).second.num<<" "<<(*it1).second.score<<endl;
    }
}
void test(){
    map<int,string> map1;
    map1.insert(pair<int,string>(10086,"中国移动"));
    map1.insert(make_pair(10000,"中国电信"));
    map1.insert(map<int,string>::value_type(10010,"中国联通"));
    map1[9527]="星爷";
    //注意map容器key不可以重复且要存在
    cout<<map1[1008]<<endl;
    cout<<map1.count(10086)<<endl;
    printMap1(map1);
}

void test1(){
    map<int,Person,less<int>> map2;
    map2.insert(make_pair(100,Person(100,"Lucy",99.99)));
    map2.insert(pair<int,Person>(200,Person(200,"Duck",99.88)));
    map2.insert(map<int,Person,less<int>>::value_type(300,Person(300,"Juck",99.98)));
    map2[101]=Person(101,"快乐崇拜",99.887);
    //cout<<map2[102]<<endl;
    cout<<map2.count(101)<<endl;
    printMap2(map2);
}

int main()
{
    test1();
    return 0;
}

输出结果:

通过比较器less<T>可以对元素进行排序,该方法可以实现类的数据操作,需要注意的是如果键值对应的实值不存在会报错,比如如上数据使用数组方法操作会报如下错误:

D:\study\STL\map\main.cpp:89: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::map<int, Person, std::less<int> >::mapped_type {aka Person}')
     cout<<map2[102]<<endl;
         ^

map的实值为类的应用 (greater比较)

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

/*
 * map构造函数
 * map<T1,T2> map1;//默认构造函数
 * map(const map &map1);//默认拷贝构造函数
 *
 * map容器赋值操作
 * map &operator=(const map &map);//重载等号运算符拷贝
 * swap(map1);//交换函数
 *
 * map容器大小操作
 * size();//返回容器元素的数目
 * empty();//判断容器是否为空
 *
 * map容器数据存取操作
 * map.insert(pair(键值,实值));//map容器元素都是对组,插入成功返回pair<iterator,bool>;
 * map<int,string> map1;
 * map1.insert(pair<int,string>(1,"张三"));
 * map1.insert(make_pair(2,"李四"));
 * map1.insert(map<int,string>::value_type(3,"张三丰"));
 * map1[4]="小王";
 * map容器的删除操作
 * map1.clear();//清空所有元素
 * erase(position);//删除position所指的元素,返回下一个元素的迭代器
 * erase(begin,end);//删除区间[begin,end)的所有元素
 * erase(keypair);//删除key为keypair的对组
 * map容器的查找操作
 * find(key);//查找key是否存在,若存在返回该key的元素的迭代器,不存在返回该容器最后一个迭代器即map1.end();
 * count(keyElement);//返回容器中key为keyElement的对组个数,注意因为map容器的特殊性,count返回的个数要么为0,要么为1
 * 而multimap则可能会返回>1
 * lower_bound(keyElement);//返回第一个key>=keyElement的元素的迭代器
 * upper_bound(keyElement);//返回第一个key>keyElement的元素的迭代器
 * equal_range(keyElement);//返回容器中key与keyElement相等的上下限的两个迭代器
 */
//自定义map容器遍历算法
void printMap1(map<int,string> &map1){
    map<int,string>::const_iterator it=map1.begin();
    for(;it!=map1.end();it++){
        //*it==pair<int,string>;注意这里的*it是map容器的元素(pair)
        cout<<(*it).first<<" "<<(*it).second<<endl;
    }
}

class Person
{
    friend void printMap2(map<int,Person,greater<int>> &map2);
public:
    Person() {}
    Person(int num,string name,double score){
        this->name=name;
        this->num=num;
        this->score=score;
    }

private:
    int num;
    string name;
    double score;
};


void printMap2(map<int,Person,greater<int>> &map2){
    map<int,Person,greater<int>>::const_iterator it1=map2.begin();
    for(;it1!=map2.end();it1++){
        cout<<(*it1).first<<" "<<(*it1).second.name<<" "<<(*it1).second.num<<" "<<(*it1).second.score<<endl;
    }
}
void test(){
    map<int,string> map1;
    map1.insert(pair<int,string>(10086,"中国移动"));
    map1.insert(make_pair(10000,"中国电信"));
    map1.insert(map<int,string>::value_type(10010,"中国联通"));
    map1[9527]="星爷";
    //注意map容器key不可以重复且要存在
    cout<<map1[1008]<<endl;
    cout<<map1.count(10086)<<endl;
    printMap1(map1);
}

void test1(){
    map<int,Person,greater<int>> map2;
    map2.insert(make_pair(100,Person(100,"Lucy",99.99)));
    map2.insert(pair<int,Person>(200,Person(200,"Duck",99.88)));
    map2.insert(map<int,Person,greater<int>>::value_type(300,Person(300,"Juck",99.98)));
    map2[101]=Person(101,"快乐崇拜",99.887);
    //cout<<map2[102]<<endl;
    cout<<map2.count(101)<<endl;
    printMap2(map2);
}

int main()
{
    test1();
    return 0;
}

输出结果:

 multimap容器

multimap容器同map容器类似,为了解决map容器键值不能重复的问题,multimap容器应运而生。

multimap容器与map容器的唯一区别就在于multimap容器允许键值重复

multimap容器原理图

 multimap容器 API

#include <iostream>
#include<map>
#include<vector>
#include<time.h>
#include<stdlib.h>

using namespace std;
/*案例:公司HR新招聘了五位新员工,5位员工进入公司后,需要分派到各个部门相应岗位上工作,HR需要录入5位员工的信息,相关信息有:姓名
 * 年龄、电话、工号、部门、工资、部门领导等信息
 */

class worker
{

    friend void inputWorker(vector<worker> &w);
    friend void workerJoinDepartment(vector<worker> &w,multimap<int,worker> &m);
    friend void showWorkerAndDepartment(multimap<int,worker> &m);

public:
    worker() {}
    worker(string name,int age,int telephone,int num,double money,string leader){
        this->name=name;
        this->age=age;
        this->leader=leader;
        this->money=money;
        this->num=num;
        this->telephone=telephone;
    }

private:
    string name;
    int age;
    int telephone;
    int num;
    double money;
    string leader;
};

void inputWorker(vector<worker> &w){
    srand(time(NULL));
    string nameTemp="ABCDE";
    int i=0;
    for(;i<5;i++){
        string name="员工";
        name+=nameTemp[i];
        int age=rand()%11+20;
        int telephone=rand();
        int num=rand()%100+101;
        double money=rand()%10001+50000;
        string leader="领导";
        leader+=nameTemp[i];
        w.push_back(worker(name,age,telephone,num,money,leader));
    }
}

void workerJoinDepartment(vector<worker> &w,multimap<int,worker> &m){
    //员工逐个分批加入各个部门
    vector<worker>::iterator it=w.begin();
    for(;it!=w.end();it++){
        cout<<"请输入"<<(*it).name<<"加入部门(1:销售,2:研发,3:财务):";
        int ob=0;
        cin>>ob;

        m.insert(make_pair(ob,*it));

    }
}

void showWorkerAndDepartment(multimap<int,worker> &m){
    cout<<"请输入需要显示的部门(1:销售,2:研发,3:财务):";
    int ob=0;
    cin>>ob;
    switch (ob) {
    case 1:
       cout<<"--------------销售部门员工-------------"<<endl;
        break;
    case 2:
       cout<<"--------------研发部门员工-------------"<<endl;
        break;
    case 3:
       cout<<"--------------财务部门员工-------------"<<endl;
        break;
    default:
        cout<<"输入的部门有误"<<endl;
        break;
    }

    multimap<int,worker>::const_iterator it2;
    it2=m.find(ob);
    if(it2!=m.end()){
        int n=m.count(ob);
        int i=0;
        for(;i<n;i++,it2++){
            cout<<"\t"<<(*it2).second.name<<" "<<(*it2).second.age<<" "<<(*it2).second.telephone<<" "<<(*it2).second.\
                  num<<" "<<(*it2).second.money<<" "<<(*it2).second.leader<<endl;
        }
    }
}

void test(){
    vector<worker> w;
    inputWorker(w);

    multimap<int,worker> m;
    workerJoinDepartment(w,m);

    showWorkerAndDepartment(m);

}

int main()
{
    test();
    return 0;
}

输出结果:

遇到cin>>不继续(bug解决办法)

tips:输入int数据的时候,差点给我整懵了,我发现使用qt自带的终端输出,一直让我输入,我一度怀疑自己的代码有问题了,仔细检查最后发现是qt 工具自带不识别

如果遇到这种情况,建议使用terminal

操作方法:左边一栏找到项目

勾选Run in terminal,(已经勾选了,也再勾选下,可能会失效所以再勾选下)

然后运行的时候就会显示terminal

unordered_map容器

与map容器、multimap容器不同,这种容器的底层实现他是基于哈希表的一种无序容器

这三种容器的区别:

  1. 有序性:std::map 和 std::multimap 是有序容器,按照键的顺序进行排序。std::map 中每个键只能对应一个值,如果插入已存在的键,则会替换旧值。std::multimap 中的键可以对应多个值,可以插入多个相同的键。

  2. 底层实现: std::map 是基于红黑树(一种自平衡的二叉搜索树)实现的有序容器,使用二叉搜索树的性质保证有序性。std::multimap 也是基于红黑树实现,但允许插入相同的键。std::unordered_map 是基于哈希表实现的无序容器,使用哈希函数将键映射到桶中,实现快速的插入、查找和删除操作。

  3. 查找效率:std::map 和 std::multimap 通过红黑树实现,每次查找的时间复杂度为 O(log n),其中 n 是容器中的元素数量。在有序情况下,可以使用二分查找进行范围查询。std::unordered_map 通过哈希表实现,平均情况下查找的时间复杂度为 O(1),最坏情况下可能达到 O(n)。由于哈希表的散列过程,无法进行范围查询。

  4. 插入和删除效率:std::map 和 std::multimap 在插入和删除操作时需要维护红黑树的平衡性,时间复杂度为 O(log n)。std::unordered_map 的插入和删除操作在平均情况下时间复杂度为 O(1),最坏情况下可能达到 O(n)。

  5. 内存占用:由于有序性的需要,std::map 和 std::multimap 在保存元素时需要额外存储红黑树的结构信息,因此相对占用的内存较多。而 std::unordered_map 的存储结构相对简单,占用的内存较少。

  6. 迭代器稳定性:对于 std::map 和 std::multimap,插入和删除元素不会导致迭代器失效,因为红黑树是自平衡的。但对于 std::unordered_map,插入和删除可能引发哈希表的重组,导致迭代器失效。因此,在使用迭代器时需要格外小心。

选择合适的关联容器取决于实际的需求,如果需要有序存储并进行范围查询,则可以选择 std::map 或 std::multimap。如果不需要特定的顺序,且对查找性能有更高的要求,则可以选择 std::unordered_map。同时要考虑到内存占用和迭代器稳定性的要求

 unordered_map API(0)

#include <iostream>
#include<unordered_map>
using namespace std;
struct Student{
    std::string name;
    int age;
    std::string major;

};

int main()
{
    unordered_map<int,Student> student;

    student[1]={"Alice",21,"Computer Science"};
    student[2]={"Bob",20,"Physics"};
    student[3]={"Lucy",22,"Mathematics"};

    int studentID=0;
    cout<<"请输入要查找的学生ID:";
    cin>>studentID;
    if(student.find(studentID)!=student.end()){
        cout<<"通过ID找到该学生"<<endl;
        cout<<"Name:"<<student[studentID].name<<" "<<student[studentID].age<<\
           " "<<student[studentID].major<<endl;

    }else{
        cout<<"通过ID未找到该学生"<<endl;
    }
    return 0;
}

输出结果:

  unordered_map API(1)

#include <iostream>
#include<unordered_map>
#include<sstream>
using namespace std;
struct Student{
    std::string name;
    int age;
    std::string major;

};

void test(){
    unordered_map<string,int> wordCount;
    string sentence="I love to code and I love to learn,but I do not love Nerve-racking.";
    istringstream iss(sentence);
    string word;
    while (iss>>word) {
       wordCount[word]++;
    }

    for(const auto& pair:wordCount){
        cout<<pair.first<<": "<<pair.second<<endl;
    }
}
void test1(){
    unordered_map<int,Student> student;

    student[1]={"Alice",21,"Computer Science"};
    student[2]={"Bob",20,"Physics"};
    student[3]={"Lucy",22,"Mathematics"};

    int studentID=0;
    cout<<"请输入要查找的学生ID:";
    cin>>studentID;
    if(student.find(studentID)!=student.end()){
        cout<<"通过ID找到该学生"<<endl;
        cout<<"Name:"<<student[studentID].name<<" "<<student[studentID].age<<\
           " "<<student[studentID].major<<endl;

    }else{
        cout<<"通过ID未找到该学生"<<endl;
    }
}

int main()
{
    test();
    return 0;
}

输出结果:

tips:这里使用了istringstream类,该类能把字符串切割为一系列的子字符串,然后通过>>输入给word,通过while循环,如果string相同则加1,同时将数据存储到unordered_map容器中,直到iss为NULL,则while循环结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值