c++ stl容器之map用法

目录

(1)map介绍

(2)map、multimap、unordered_map区别

(3)map用法

1.map接口表

2.使用举例

插入数据与遍历数据

查找关键字和值

删除元素

按照值排序

(4)multimap用法

(5)unordered_map用法


(1)map介绍

map是STL的一个关联容器,以键值对存储的数据,其类型可以自己定义,每个关键字在map中只能出现一次,关键字不能修改,值可以修改。

map同set、multiset、multimap内部数据结构都是红黑树,而java中的hashmap是以hash table实现的。所以map内部有序(自动排序,单词时按照字母序排序),查找时间复杂度为O(logn)。

multimap与map的差别仅在于multimap允许键重复,有多个相同的键,而map要求键的唯一性。

(2)map、multimap、unordered_map区别

在C++中,std::map和std::unordered_map都是关联容器,它们存储的元素都是键值对(key-value pairs),并且每个键在容器中都是唯一的。然而,它们在内部实现、性能特性以及适用场景上有所不同。

对于std::map(基于红黑树实现),insert()函数会保持元素的排序顺序。而对于std::unordered_map(基于哈希表实现),元素的顺序是随机的。

主要区别如下表:

特性

std::map

std::multimap

std::unordered_map

键的唯一性

键唯一(不允许重复)

键可重复(允许重复)

键唯一(不允许重复)

元素有序性

按键升序排序(红黑树实现)

按键升序排序(红黑树实现)

无序(哈希表实现)

查找复杂度

O(log N)

O(log N)

平均 O(1),最坏 O(N)(哈希冲突)

插入/删除复杂度

O(log N)

O(log N)

平均 O(1),最坏 O(N)(哈希冲突)

适用场景

需要有序遍历或范围查询

需要有序遍历且键可重复

需要快速查找且不关心顺序

在选择使用std::map还是std::unordered_map时,你需要考虑你的具体需求。如果你需要元素保持排序或者对迭代器稳定性有要求,那么应该使用std::map。如果你对性能有严格要求,并且可以接受非确定性的迭代顺序,那么应该使用std::unordered_map。

(3)map用法

1.map接口表

操作

示例

构造对象

#include

// 第一种

map mymap1;

// 也可以这样

typedef map My_Map;

My_Map mymap2;

insert() 插入数据

插入单个元素

std::map myMap;

myMap.insert(std::pair(1, "one"));

// 或者使用make_pair

myMap.insert(std::make_pair(2, "two"));

// 或者使用初始化列表(C++11及更高版本)

myMap.insert({3, "three"});

检查是否插入成功

auto result = myMap.insert(std::pair(1, "one"));

if (result.second == false) {

// 插入失败,键1已存在

}

插入多个元素

std::vector> elements = {{4, "four"}, {5, "five"}};

myMap.insert(elements.begin(), elements.end());

// 或者使用初始化列表(C++11及更高版本)

myMap.insert({{6, "six"}, {7, "seven"}});

从C++11开始,std::map和std::unordered_map都提供了emplace()函数,该函数允许你直接在容器中构造元素,这通常比先构造一个临时对象然后再插入更高效。

myMap.emplace(1, "one"); // 直接在map中构造元素

find() 查找元素

// 查找键为2的元素  

    auto it = myMap.find(2);  

    if (it != myMap.end()) {  

  // 找到

    } else {  

        std::cout << "Key 2 not found." << std::endl;  

    }  

clear() 清空元素

    // 清除映射中的所有元素  

    myMap.clear();  

erase() 删除一个元素

myMap.erase(2); // 移除键为2的元素

auto it = myMap.find(3); // 查找键为3的元素的迭代器

if (it != myMap.end()) {

myMap.erase(it); // 移除找到的元素

}

// 假设我们想移除所有键在2到4(包括2但不包括4)之间的元素

auto range_start = myMap.lower_bound(2); // 找到第一个不小于2的元素的迭代器

auto range_end = myMap.upper_bound(4); // 找到第一个大于4的元素的迭代器

myMap.erase(range_start, range_end); // 移除范围内的元素

erase()会返回指向下一个有效元素的迭代器。

my_map.size()

map的长度大小

my_map.begin()

返回指向map头部的迭代器

my_map.end()

返回指向map末尾的迭代器

my_map.rbegin()

返回一个指向map尾部的逆向迭代器

my_map.rend()

返回一个指向map头部的逆向迭代器

my_map.empty()

map为空时返回true

swap()

交换两个map,两个map中所有元素都交换

2.使用举例

插入数据与遍历数据

通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据iterator->first和iterator->second,分别代表关键字和value值。

在C++中,std::map默认就是按照键(key)的升序进行排序和存储的。因此,你只需要使用标准的迭代器来遍历std::map,就可以按照键的升序来获取元素。

#include 
using namespace std;

#include 

// 自定义打印map的函数
void printMap(map mymymap)
{
    cout << "----------" << endl;
    map::iterator it;
    for (it = mymymap.begin(); it != mymymap.end(); it++)
        cout << it->first << "=" << it->second << endl; // key=value
    cout << "----------" << endl;
}

int main()
{
    map mymap;

    //第一种:用insert函数插入pair数据
    mymap.insert(pair("first", 1));
    mymap.insert(pair("second", 2));

    //第二种:用insert函数插入value_type数据
    mymap.insert(map::value_type("third", 3));
    mymap.insert(map::value_type("fourth", 4));

    //迭代器遍历
    map::iterator it;
    cout << "----------" << endl;
    for (it = mymap.begin(); it != mymap.end(); it++)
        cout << it->first << "=" << it->second << endl; // key=value
    cout << "----------" << endl;

    //第三种:更简便
    mymap["first"] = 100;
    mymap["fifth"] = 5;  //新加入的元素会被放到容器的第一个位置
    printMap(mymap);

    return 0;
}

查找关键字和值

第一种:用count函数来判断关键字是否出现,其缺点是无法定位元素出现的位置。由于map一对一的映射关系,count函数的返回值要么是0,要么是1。

#include 
using namespace std;

#include 

int main()
{
    map my_map;
    my_map["first"] = 1;
    cout << my_map.count("first") << endl; //输出1
    cout << my_map.count("second") << endl; //输出0

    return 0;
}

第二种:用find函数来定位元素出现的位置,它返回一个迭代器,当数据出现时,返回的是数据所在位置的迭代器;若map中没有要查找的数据,返回的迭代器等于end函数返回的迭代器。

#include 
#include 
#include 

using namespace std;

int main()
{
    map my_map;

    my_map.insert(pair(1, "student_one"));
    my_map.insert(pair(2, "student_two"));
    my_map.insert(pair(3, "student_three"));

    map::iterator it;

    it = my_map.find(1);
    if (it != my_map.end())
        cout << "Find, the value is " << it->second << endl;
    else
        cout << "Do not Find" << endl;

    it = my_map.find(4);
    if (it != my_map.end())
        cout << "Find, the value is " << it->second << endl;
    else
        cout << "Do not Find" << endl;

    return 0;
}

删除元素

map对象的erase函数传入参数即可以是迭代器又可以是key

#include 
#include 
#include 

using namespace std;

void printMap(map mymymap)
{
    cout << "----------" << endl;
    map::iterator it;
    for (it = mymymap.begin(); it != mymymap.end(); it++)
        cout << it->first << "=" << it->second << endl; // key=value
    cout << "----------" << endl;
}

int main()
{
    map my_map;
    my_map.insert(pair(1, "one"));
    my_map.insert(pair(2, "two"));
    my_map.insert(pair(3, "three"));
    my_map.insert(pair(4, "fourth"));
    printMap(my_map);

    // 第1种,用迭代器删除 关键字为 1 的数据
    map::iterator it;
    it = my_map.find(1);
    my_map.erase(it);        //如果要删除1,用关键字删除

    printMap(my_map);

    // 第2种,直接用关键字删除
    int n = my_map.erase(2); //如果成功删除了会返回1,否则返回0

    printMap(my_map);

    // 第2种,用迭代器,成片的删除,可以达到直接清空所有数据
    my_map.erase(my_map.begin(), my_map.end());
    // 成片删除要注意的是,也是STL的特性,删除区间是一个左闭右开的集合
    printMap(my_map);

    return 0;
}

按照值排序

map中元素是自动按key升序排序(从小到大)的;按照value排序时,想直接使用sort函数是做不到的,sort函数只支持数组、vector、list、queue等的排序,无法对map排序,那么就需要把map放在vector中,再对vector进行排序。

例子1

#include 
#include 
#include 
#include 
#include 
using namespace std;

void printMap(map mymymap)
{
    cout << "----------" << endl;
    map::iterator it;
    for (it = mymymap.begin(); it != mymymap.end(); it++)
        cout << it->first << "=" << it->second << endl; // key=value
    cout << "----------" << endl;
}

bool cmp(pair a, pair b)
{
    return a.second < b.second; // 严格升序
}

int main()
{
    map ma;
    ma["Alice"] = 86;
    ma["Bob"] = 78;
    ma["Zip"] = 92;
    ma["Stdevn"] = 88;
    printMap(ma);

    // 第一种方式传递到vector中
    vector> vec(ma.begin(), ma.end());

    // 第二种方式传递到vector中
    vector> vec2;
    for (map::iterator it = ma.begin(); 
                                    it != ma.end(); it++)
        vec2.push_back(pair(it->first, it->second));
    
    // std::pair tempPair(name, grade);      

    // 对vec排序
    sort(vec.begin(), vec.end(), cmp);
    for (vector>::iterator it = vec.begin(); 
                                        it != vec.end(); ++it)
    {
        cout << it->first << "=" << it->second << endl;
    }

    return 0;
}

例子2

#include   
#include   
#include   
#include   
#include   

bool judge_func(const std::pair& a, const std::pair& b){

    return a.second < b.second;  // 严格弱序比较
    // 等值的元素在排序后的序列中保持其原始相对顺序
    // return a.second <= b.second;  // 非严格弱序比较
    // 在大多数情况下,你应该使用严格弱序比较(即a.second < b.second)来确保排序的稳定性和可预测性
}

  
int main() {  
    std::map m = {{1, "Z"}, {2, "B"}, {3, "A"}, {4, "C"}};  
  
    std::vector> v(m.begin(), m.end());  
    
    // c++中sort方法使用匿名函数排序
    //  [](参数a, 参数b){函数体返回bool, a.x < b.x /*返回true表示升序*/}
    // std::sort(v.begin(), v.end(), [](const std::pair& a, const std::pair& b) {  
    //     return a.second < b.second;  
    // });  

    // 有名函数排序
    std::sort(v.begin(), v.end(), judge_func);
  
    // 输出排序后的结果  
    for (const auto& pair : v) {  
        std::cout << pair.first << ": " << pair.second << std::endl;  
    }  
  
    return 0;  
}

(4)multimap用法

multimap是关联式容器,按照特定顺序存储键值对,其中多个键值对之间的key可以重复。

multimap与map唯一不同就是,map中key是唯一的,multimap中key是可以重复的。

Multimap 案例:

  • 1个key值可以对应多个valude  =分组 
  • 公司有销售部 sale (员工2名)、技术研发部 development (2人)、财务部 Financial (2人) 
  • 人员信息有:姓名,年龄,电话、工资等组成
  • 通过 multimap进行 信息的插入、保存、显示
  • 分部门显示员工信息
  • 按条件搜索修改
#include 
#include 
#include 
using namespace std;

class Person
{
public:
    string name;
    int age;
    string telephone;
    double salary;
};

void test()
{
    Person p1, p2, p3, p4, p5, p6;

    p1.name = "王1";
    p1.age = 31;

    p2.name = "王2";
    p2.age = 32;

    p3.name = "张3";
    p3.age = 33;

    p4.name = "赵4";
    p4.age = 35;

    p5.name = "张5";
    p5.age = 34;

    p6.name = "赵6";
    p6.age = 35;

    // 1.构造
    multimap map2;

    // 2.插入数据
    //sale部门
    map2.insert(make_pair("sale", p1) );
    map2.insert(make_pair("sale", p2) );
    //development 部门
    map2.insert(make_pair("development", p3) );
    map2.insert(make_pair("development", p5) );
    //Financial 部门
    map2.insert(make_pair("Financial", p4) );
    map2.insert(make_pair("Financial", p6) );

    // 3.遍历multimap类型
    multimap::iterator it = map2.begin();
    for (it; it != map2.end(); it++)
    {
        cout << it->first << "\t" << it->second.name << endl;
    }
    /*
    Financial   赵4
    Financial   赵6
    development 张3
    development 张5
    sale    王1
    sale    王2
    */

    // 4.统计development部门的人数
    int num2 = map2.count("development");
    cout << "development num = " << num2 << endl;  // 2

    // 5.查找development部门员工信息
    // find若查找到则出现在第一次位置,若未查找到则map2.end()
    multimap::iterator it2 = map2.find("development");
    int tag = 0;
    while (it2 != map2.end() && tag < num2)
    {
        cout << it2->first << "\t" << it2->second.name << endl;
        it2++;
        tag++;
    }
    /*
    development 张3
    development 张5
    */

    // 可以注意到multimap会将同一个key的多个value挨着
    // 所以这里用find方法得到的迭代器再++时,全是development部门的值

    // 6.按照条件 检索数据 进行修改
    cout << "-----------------" << endl;
    for(multimap::iterator it=map2.begin(); it!=map2.end(); it++)
    {
        if (it->second.age == 32 )
        {
            it->second.name = "name32";
        }
    }

    for( multimap::iterator it=map2.begin(); it!=map2.end(); it++)
    {
        cout << it->first << "\t" << it->second.age << "\t" << it->second.name << endl;
    }
    /*
    Financial   35  赵4
    Financial   35  赵6
    development 33  张3
    development 34  张5
    sale    31  王1
    sale    32  name32
    */
}


int main()
{
    test();

    return 0;
}

(5)unordered_map用法

  • 键唯一性:每个键只能出现一次,重复插入会覆盖原有值。
  • 无序性:元素存储顺序不确定(由哈希函数决定)。
  • 底层实现:基于哈希表(哈希桶 + 链表或树)。

适用场景:

需要快速查找、插入或删除,且不关心顺序。示例:缓存系统、字典查询。

例子

#include 
#include 

int main() {
    std::unordered_map umap = {
        {1, "Alice"},
        {2, "Bob"},
        {3, "Charlie"}
    };

    // 输出顺序不确定(可能是 2, 3, 1 或其他)
    for (const auto& [key, value] : umap) {
        std::cout << key << ": " << value << std::endl;
    }
    // 可能的输出:
    // 2: Bob
    // 3: Charlie
    // 1: Alice
}


end

你可能感兴趣的:(c++之STL,c++,stl,map,unordered_map)