C++容器map的常见用法

1.map和multimap容器

在C++ STL(标准模板库)中,mapmultimap是两种关联容器,它们用于存储键值对,其中每个键都是唯一的,并且与一个特定的值相关联。然而,它们之间存在一些关键区别:

map

  1. 唯一性map中的键是唯一的,也就是说,一个键只能对应一个值。如果你尝试插入一个键值对,而该键已经存在于map中,那么原有的键对应的值将被新值替换。

  2. 排序map中的元素按照键的升序(默认情况下)进行排序。这是通过比较键实现的,可以自定义比较函数来改变排序方式。

  3. 基本操作:主要操作包括插入(insert)、删除(erase)、查找(find)和访问(直接通过键访问,如map[key])元素。

multimap

  1. 非唯一性:与map的主要区别在于,multimap允许有多个相同的键,每个键可以对应多个不同的值。这意味着当你插入一个键已经存在的键值对时,新值会被添加到该键已有的值集合中,而不是替换原有值。

  2. 排序:和map一样,multimap中的元素也是根据键进行排序的,可以是升序或根据自定义的比较函数排序。

  3. 基本操作:除了与map共享的基本操作外,由于可能有多个相同键的存在,multimap的查找操作(如find)可能会返回一个迭代器范围,表示所有匹配键的值集合。

使用场景

  • map适用于当你需要确保每个键只对应一个值,且经常需要根据键快速查找或更新其关联值的场景。

  • multimap适合那些一个键可能对应多个值,且在查询时你可能关心所有与某一键相关联的值的情况,比如存储学生的分数时,如果有多个学生获得相同的分数,multimap能很好地处理这种情况。

1.map容器的构造和赋值

在C++中,std::map容器提供了多种构造函数和赋值操作,以方便初始化和管理键值对数据。

1.构造函数
  1. 默认构造函数

    std::map<Key, T> m; // 创建一个空的map,默认按键升序排序。
    
  2. 拷贝构造函数

    std::map<Key, T> m1;
    // 假设m1已经被初始化
    std::map<Key, T> m2(m1); // m2是m1的一个拷贝
    
  3. 使用比较函数构造

    struct MyCompare {
        bool operator()(const Key& lhs, const Key& rhs) const {
            // 自定义比较逻辑
            return lhs < rhs; // 示例:使用默认比较
        }
    };
    std::map<Key, T, MyCompare> m(MyCompare()); // 使用自定义比较函数
    
  4. 区间构造

    std::map<Key, T> m.begin(), m.end());
    // 或者使用其他容器/迭代器范围
    std::vector<std::pair<Key, T>> vec;
    // 假设vec已被填充
    std::map<Key, T> m(vec.begin(), vec.end());
    
2.赋值操作
  1. 拷贝赋值运算符

    std::map<Key, T> m1, m2;
    // 假设m1和m2已经被初始化
    m1 = m2; // 将m2的内容赋值给m1
    
  2. 初始化列表赋值(C++11及以上)

    std::map<Key, T> m = { {key1, value1}, {key2, value2}, ... };
    
  3. 区间赋值

    std::map<Key, T> m1, m2;
    // 假设m2已被填充
    m1.assign(m2.begin(), m2.end());
    
  4. 插入迭代器对
    虽然这不是直接的赋值操作,但可以通过迭代器对插入元素来“赋值”或填充map。

    std::map<Key, T> m;
    std::vector<std::pair<Key, T>> vec;
    // 假设vec已被填充
    m.insert(vec.begin(), vec.end());
    

这些构造和赋值方法提供了灵活的方式来创建和管理std::map容器,满足不同场景下的需求。

 ```cpp
 #include <iostream>
 #include <map>
 
 // 使用标准命名空间,简化后续代码中的类型名称
 using namespace std;
 
 /**
  * 打印map的内容
  * @param m 一个整数到整数的映射,其内容将被打印
  */
 void printMap(const map<int,int>& m){
     // 遍历映射中的所有元素,并打印每个元素的键和值
     for(auto it : m){
         cout << it.first << " " << it.second << endl;
     }
 }
 
 int main(){
     // 初始化一个map,包含两个元素
     map<int,int> m = {{1,2},{2,4}};
     // 创建一个对m的常量引用,以避免复制map的内容
     const map<int,int>& m1(m);
     // 调用函数打印map的内容
     printMap(m);
     printMap(m1);
     // 初始化一个空的map,并将其设置为与m相同的内容
     map<int,int> m2;
     m2 = m;
     printMap(m2);
 
     return 0;
 }
 ```
2.map容器的大小和交换

在C++的STL中,std::map容器提供了以下与大小和交换相关的成员函数:

1.获取大小
  • size(): 此函数返回map中元素的数量,即键值对的总数。

    std::map<Key, T> myMap;
    // ... 添加元素到myMap
    std::cout << "Size of the map: " << myMap.size() << std::endl;
    
  • empty(): 判断map是否为空,如果容器中没有元素,则返回true,否则返回false

    if (myMap.empty()) {
        std::cout << "The map is empty." << std::endl;
    } else {
        std::cout << "The map is not empty." << std::endl;
    }
    
2.交换内容
  • swap(std::map<Key, T>& other): 此函数交换两个map容器的内容,交换操作高效执行,不会涉及元素的复制或移动。

    std::map<Key, T> myMap1, myMap2;
    // ... 分别填充myMap1和myMap2
    myMap1.swap(myMap2);
    // 现在myMap1包含myMap2原来的内容,反之亦然
    

这些函数允许检查容器的当前状态(是否为空,包含多少元素)以及重新分配两个容器的内容,而无需创建新的容器副本。这对于优化内存使用和性能特别有用。

//
// Created by 86189 on 2024/7/3.
//
#include <iostream>
#include <map>

// 使用标准命名空间,简化后续代码中标准库类型的引用
using namespace std;

/**
 * 打印map的内容
 * @param m 一个整数到整数的映射,其内容将被打印
 */
void printMap(const map<int,int>& m){
    // 遍历map,打印每个键值对
    for(auto it : m){
        cout << it.first << " " << it.second << endl;
    }
}

int main(){
    // 初始化一个map,包含两个元素
    map<int,int> m{{1,2},{2,4}};
    // 调用函数打印map内容
    printMap(m);
    // 打印map的大小
    cout << m.size() << endl;
    // 检查map是否为空,如果不为空,则再次打印其内容
    if(!m.empty()){
        printMap(m);
    }
    // 初始化另一个空的map
    map<int,int> m1;
    // 交换两个map的内容
    m.swap(m1);
    // 分别打印交换后的两个map的内容
    printMap(m);
    printMap(m1);
    return 0;
}
3.map容器的插入和删除

在C++的STL中,std::map容器提供了丰富的成员函数来进行元素的插入和删除操作。以下是几种常见的插入和删除方法:

1.插入元素
  1. insert(const value_type& val): 插入一个键值对。如果键已存在,则不会插入重复的键。

    myMap.insert(std::make_pair(key, value));
    // 或者使用直接初始化语法(C++11起)
    myMap.insert({key, value});
    
  2. insert(iterator hint, const value_type& val): 尝试在迭代器hint指向的位置附近插入元素,以提高效率。如果hint恰好指向要插入位置的下一个位置,则插入操作可能更快。

    auto it = myMap.lower_bound(key);
    myMap.insert(it, std::make_pair(key, value));
    
  3. insert(initializer_list<value_type> ilist): 从初始化列表插入多个键值对(C++11起)。

    myMap.insert({ {key1, value1}, {key2, value2}, ... });
    
2.删除元素
  1. erase(iterator position): 删除迭代器position指向的元素。

    auto it = myMap.find(key);
    if (it != myMap.end()) {
        myMap.erase(it);
    }
    
  2. erase(const key_type& key): 删除具有指定键的元素。

    myMap.erase(key);
    
  3. erase(iterator first, iterator last): 删除迭代器范围[first, last)内的所有元素。

    auto startIt = myMap.lower_bound(startKey);
    auto endIt = myMap.upper_bound(endKey);
    myMap.erase(startIt, endIt);
    
3.注意事项
  • 在删除元素后,之前指向被删除元素的迭代器、指针和引用都会变得无效。
  • erase返回的是下一个元素的迭代器,这在连续删除元素时很有用。
  • 对于insert操作,如果试图插入的键已经存在,该操作不会改变容器且不会抛出异常(除非因内存分配失败)。

通过这些方法,你可以有效地管理std::map容器中的数据,无论是添加新元素还是移除不需要的条目。

//
// Created by 86189 on 2024/7/3.
//
#include <iostream>
#include <map>

// 使用标准命名空间,简化后续代码中标准库类型的引用
using namespace std;

/**
 * 打印map的内容
 * @param m 一个整数到整数的映射,其内容将被打印
 */
void printMap(const map<int,int>& m){
    // 遍历map,打印每个键值对
    for(auto it : m){
        cout << it.first << " " << it.second << endl;
    }
}

int main(){
    // 初始化一个map,包含两个元素
    map<int,int> m{{1,2},{2,4}};
    // 调用函数打印map内容
    printMap(m);
    // 打印map的大小
    cout << m.size() << endl;
    // 检查map是否为空,如果不为空,则再次打印其内容
    if(!m.empty()){
        printMap(m);
    }
    // 初始化另一个空的map
    map<int,int> m1;
    // 交换两个map的内容
    m.swap(m1);
    // 分别打印交换后的两个map的内容
    printMap(m);
    printMap(m1);
    return 0;
}
4.map容器的查找和统计

在C++的STL中,std::map容器提供了几种查找和统计元素的方法:

1.查找元素
  1. find(const key_type& k): 返回一个迭代器,指向键为k的第一个元素。如果找不到这样的元素,则返回end()

    auto it = myMap.find(key);
    if (it != myMap.end()) {
        std::cout << "Found element with key: " << it->first << ", value: " << it->second << std::endl;
    } else {
        std::cout << "Element not found." << std::endl;
    }
    
  2. count(const key_type& k): 返回键为k的元素数量。对于map,由于键唯一,此函数要么返回0(表示不存在),要么返回1(表示存在)。

    size_t count = myMap.count(key);
    if (count > 0) {
        std::cout << "Key exists in the map." << std::endl;
    } else {
        std::cout << "Key does not exist in the map." << std::endl;
    }
    
2.统计元素

map容器中,由于键的唯一性,统计通常较为直接,主要依赖于count函数来确定某个键是否存在。对于键值对的计数,通常意义不大,因为每个键最多只能对应一个值。但在多值映射multimap中,count可以有效统计相同键值出现的次数。

3.示例

假设有一个std::map<int, std::string>类型的myMap,以下是如何使用查找和统计方法的简单示例:

#include <iostream>
#include <map>

// 使用标准命名空间,简化后续代码中标准库的调用
using namespace std;

/**
 * 打印map中的所有元素
 * @param m 一个整数到整数的映射,其元素将被打印
 */
void printMap(const map<int,int>& m){
    // 遍历map中的每个元素,并打印其键值对
    for(auto it : m){
        cout << it.first << " " << it.second << endl;
    }
}

int main(){
    // 初始化一个map,包含两个元素:{1, 2} 和 {2, 4}
    map<int,int> m{{1,2},{2,4}};
    
    // 寻找键值为1的元素
    auto it = m.find(1);

    cout << it->first << endl;
    // 检查是否找到键值为1的元素
    if(it != m.end()){
        cout << "in" << endl;
    } else{
        cout << "no" << endl;
    }
    
    // 调用函数打印map的所有元素
    printMap(m);
    
    // 打印键值为1的元素在map中出现的次数
    cout << m.count(1) << endl;
    
    return 0;
}
5.map容器的排序

std::map容器在C++ STL中自动保持其元素有序。默认情况下,元素是按照键(key)的升序进行排序的。这种排序是由比较函数决定的,std::map默认使用std::less<Key>作为比较器,它提供了一个严格弱序的比较,适用于大多数基本数据类型。

1.自定义排序规则

尽管std::map默认按key排序,但如果你想改变排序逻辑,可以在创建map时指定一个自定义的比较函数对象。例如,如果你想让map按照key降序排列,或者基于键的某些复杂属性排序,你可以这样做:

struct CustomCompare {
    bool operator()(const Key& lhs, const Key& rhs) const {
        // 自定义比较逻辑,例如降序排序:
        return rhs < lhs; // 改变比较逻辑以实现降序
    }
};

std::map<Key, Value, CustomCompare> myMap;
2.注意点
  • 不可更改排序:一旦map实例化,其排序规则就不能再改变。如果需要改变排序,你需要创建一个新的map实例并使用不同的比较函数。
  • 基于value排序:如果需要按照value排序,std::map本身不直接支持。一个常见做法是将map的元素复制到一个std::vector中,每个元素是一个键值对(例如,使用std::pair<Key, Value>),然后对这个vector进行排序。可以使用std::sort函数配合自定义的比较器来达到目的。
3.示例:基于value排序
std::map<Key, Value> originalMap;
// ... 填充originalMap

std::vector<std::pair<Key, Value>> items(originalMap.begin(), originalMap.end());
std::sort(items.begin(), items.end(), [](const std::pair<Key, Value>& a, const std::pair<Key, Value>& b) {
    return a.second > b.second; // 降序排序基于value
});

// 现在items是按value排序的键值对集合

综上所述,虽然std::map自动维持其内部元素的排序(基于键),但通过自定义比较函数,可以控制排序逻辑。而对于基于value的排序,则需借助额外的数据结构和排序算法。

//
// Created by 86189 on 2024/7/3.
//
#include <iostream>
#include <map>
using namespace std;

// 自定义比较函数对象,用于map中键值的降序排序
class Compare{
public:
    // 比较两个整数,返回true如果第一个大于第二个
    bool operator()(const int &a,const int &b) const{
        return a > b;
    }
};

// 打印map中的所有元素
// 参数m: 使用自定义比较函数对象Compare的map
void printMap(const map<int, int, Compare>& m){
    // 遍历map中的每个元素并打印
    for(auto it : m){
        cout << it.first << " " << it.second <<endl;
    }
}

int main(){
    // 初始化一个使用自定义比较函数对象的map
    map<int,int,Compare>m{{1,2},{2,4},{3,5}};
    // 调用函数打印map内容
    printMap(m);
    return 0;
}
  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FightingLod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值