C++STL(6) map容器汇总

C++STL(6) map容器汇总

目录

  • C++STL(6) map容器汇总
  • 一、概述
  • 二、构造方法
  • 三、常用成员函数
  • 四、std::map 的优缺点

一、概述

std::map是C++标准库中的关联容器之一,它提供了一种键-值对的存储方式,其中每个键都是唯一的。std::map基于红黑树的数据结构实现,具有以下特点:

  1. 键的唯一性:std::map中的每个键都是唯一的,同一个键只能对应一个值。这使得std::map非常适用于需要通过键来查找和访问值的场景。

  2. 自动排序:std::map中的键按照严格弱序进行排序,这意味着它们按照升序排列。默认情况下,std::map使用键的比较操作符 < 来进行排序,但也可以通过自定义比较函数来实现自定义排序。

  3. 快速查找:由于std::map是基于红黑树实现的,它具有快速的查找性能。std::map提供的find函数可以在O(logN)的时间复杂度内查找特定的键。

  4. 动态扩展:std::map是动态扩展的,可以根据需要动态添加或删除键值对,而不需要事先知道容器的大小。

除了上述基本特点外,std::map还提供了其他一些有用的功能和操作,如:

需要注意的是,由于std::map是有序的,插入和删除操作的效率相对较低,平均时间复杂度为O(logN)。因此,如果需要频繁地进行插入和删除操作,可能需要考虑其他数据结构,如std::unordered_map

总结而言,std::map是一种键-值对的关联容器,具有键的唯一性、自动排序和快速查找的特点。它在许多场景中都是一个强大而有用的工具,特别适用于需要通过键来查找和访问值的情况。

二、构造方法

std::map提供了多种构造方法来创建和初始化对象。以下是几种常用的构造方法及其代码示例:

  1. 默认构造函数:
#include 
#include 

int main() {
    std::map<int, std::string> myMap;  // 默认构造一个空的map

    myMap[1] = "One";
    myMap[2] = "Two";
    myMap[3] = "Three";

    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}
  1. 区间构造函数:
#include 
#include 
#include 

int main() {
    std::vector<std::pair<int, std::string>> pairs = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    std::map<int, std::string> myMap(pairs.begin(), pairs.end());

    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}
  1. 拷贝构造函数:
#include 
#include 

int main() {
    std::map<int, std::string> originalMap = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    std::map<int, std::string> copiedMap(originalMap);  // 使用拷贝构造函数创建副本

    for (const auto& pair : copiedMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}
  1. 移动构造函数(C++11及以上):
#include 
#include 
#include 

int main() {
    std::map<int, std::string> originalMap = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    std::map<int, std::string> movedMap(std::move(originalMap));  // 使用移动构造函数创建新的map,并接管原始map的资源

    for (const auto& pair : movedMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

这些是std::map的几种常用构造方法的示例。每种构造方法都有其特定的用途和适用场景,您可以根据自己的需求选择合适的构造方法来创建和初始化std::map对象。

三、常用成员函数

当然!下面是对上述插入元素的成员函数进行的示例:

使用insert插入一个键值对或一个区间的键值对:

#include 
#include 

int main() {
    std::map<int, std::string> myMap;

    // 插入单个键值对
    myMap.insert(std::make_pair(1, "One"));

    // 插入多个键值对
    myMap.insert({{2, "Two"}, {3, "Three"}});

    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

使用emplace在原地构造一个键值对并插入:

#include 
#include 

int main() {
    std::map<int, std::string> myMap;

    // 使用 emplace 在原地构造键值对并插入
    myMap.emplace(1, "One");
    myMap.emplace(2, "Two");
    myMap.emplace(3, "Three");

    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

使用emplace_hint在给定位置处尝试插入一个键值对:

#include 
#include 

int main() {
    std::map<int, std::string> myMap;

    // 先插入一个键值对
    myMap.insert(std::make_pair(1, "One"));

    // 使用 emplace_hint 在给定位置处尝试插入键值对
    auto hint = myMap.find(1);  // 查找插入位置的迭代器
    myMap.emplace_hint(hint, 2, "Two");
    myMap.emplace_hint(hint, 3, "Three");

    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

这些示例演示了std::map中常用的插入元素的成员函数。您可以根据需要选择适合的函数来插入键值对或一组键值对,并根据迭代器的位置来控制插入的位置。

以下是一些std::map的其他常用成员函数:

  1. 访问元素:

    • operator[]:通过键访问对应的值,如果键不存在则会插入新的键值对。
    • at:通过键访问对应的值,如果键不存在会抛出异常。
    • find:根据键查找对应的迭代器,如果键不存在则返回尾后迭代器。
  2. 删除元素:

    • erase:根据键或迭代器删除一个或多个键值对。
    • clear:清空std::map中的所有键值对。
  3. 容量和状态:

    • size:返回std::map中键值对的数量。
    • empty:检查std::map是否为空。
  4. 迭代器操作:

    • begin:返回指向第一个键值对的迭代器。
    • end:返回指向尾后位置的迭代器。

下面是一些示例代码,展示了这些成员函数的用法:

访问元素:

#include 
#include 

int main() {
    std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    // 使用 operator[] 访问值,如果键不存在则插入新的键值对
    std::cout << myMap[1] << std::endl;  // 输出 "One"

    // 使用 at 访问值,如果键不存在则抛出异常
    try {
        std::cout << myMap.at(4) << std::endl;  // 抛出 std::out_of_range 异常
    } catch (const std::out_of_range& e) {
        std::cout << "Key not found: " << e.what() << std::endl;
    }

    // 使用 find 查找键对应的迭代器
    auto it = myMap.find(2);
    if (it != myMap.end()) {
        std::cout << "Found: " << it->second << std::endl;  // 输出 "Two"
    } else {
        std::cout << "Key not found." << std::endl;
    }

    return 0;
}

删除元素:

#include 
#include 

int main() {
    std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    // 根据键删除键值对
    myMap.erase(2);

    // 使用迭代器删除键值对
    auto it = myMap.find(3);
    if (it != myMap.end()) {
        myMap.erase(it);
    }

    // 清空 map 中的所有键值对
    myMap.clear();

    return 0;
}

容量和状态:

#include 
#include 

int main() {
    std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    // 获取键值对的数量
    std::cout << "Size: " << myMap.size() << std::endl;

    // 检查 map 是否为空
    if (myMap.empty()) {
        std::cout << "Map is empty." << std::endl;
    } else {
        std::cout << "Map is not empty." << std::endl;
    }

    return 0;
}

迭代器操作:

#include 
#include 

int main() {
    std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    // 使用迭代器遍历键值对
    for (auto it = myMap.begin(); it != myMap.end(); ++it) {
        std::cout << it->first << ": " << it->second << std::endl;
    }

    return 0;
}

这些示例演示了std::map的一些常用成员函数,用于访问、删除和操作键值对,以及获取容量和迭代器操作。您可以根据具体的需求选择适当的成员函数来操作std::map对象。

  1. 查找元素:

    • count:返回给定键在std::map中出现的次数,因为std::map中键是唯一的,所以返回值只能是0或1。
    • lower_bound:返回一个迭代器,指向std::map中第一个不小于给定键的元素。
    • upper_bound:返回一个迭代器,指向std::map中第一个大于给定键的元素。
    • equal_range:返回一个std::pair,包含一个迭代器范围,表示与给定键相等的元素范围。
  2. 比较和排序:

    • key_comp:返回一个用于比较键的函数对象。
    • value_comp:返回一个用于比较键值对的函数对象。
    • get_allocator:返回与std::map关联的分配器。

下面是一些示例代码,演示了这些成员函数的用法:

查找元素:

#include 
#include 

int main() {
    std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    // 使用 count 统计给定键的出现次数
    int count = myMap.count(2);
    std::cout << "Count: " << count << std::endl;  // 输出 1

    // 使用 lower_bound 查找第一个不小于给定键的元素
    auto lower = myMap.lower_bound(2);
    if (lower != myMap.end()) {
        std::cout << "Lower bound: " << lower->first << ": " << lower->second << std::endl;  // 输出 "2: Two"
    }

    // 使用 upper_bound 查找第一个大于给定键的元素
    auto upper = myMap.upper_bound(2);
    if (upper != myMap.end()) {
        std::cout << "Upper bound: " << upper->first << ": " << upper->second << std::endl;  // 输出 "3: Three"
    }

    // 使用 equal_range 获取与给定键相等的元素范围
    auto range = myMap.equal_range(2);
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << "Equal range: " << it->first << ": " << it->second << std::endl;  // 输出 "2: Two"
    }

    return 0;
}

比较和排序:

#include 
#include 

int main() {
    std::map<int, std::string> myMap = {{1, "One"}, {2, "Two"}, {3, "Three"}};

    // 获取用于比较键的函数对象
    auto comp = myMap.key_comp();

    // 使用函数对象比较键
    bool result = comp(1, 2);
    std::cout << "Comparison result: " << result << std::endl;  // 输出 1 (true)

    // 获取用于比较键值对的函数对象
    auto valueComp = myMap.value_comp();

    // 使用函数对象比较键值对
    result = valueComp(std::make_pair(1, "One"), std::make_pair(2, "Two"));
    std::cout << "Comparison result: " << result << std::endl;  // 输出 1 (true)

    // 获取与 std::map 关联的分配器
    auto allocator = myMap.get_allocator();
    // 使用分配器进行内存分配等操作...

    return 0;
}

四、std::map 的优缺点

std::map是C++标准库提供的关联容器之一,它基于红黑树实现。以下是std::map的一些优点和缺点:

优点:

  1. 有序性std::map中的键值对按照键的顺序进行排序,这使得对键的范围查询和遍历操作非常高效。
  2. 唯一键std::map中的键是唯一的,每个键只能对应一个值。这对于需要确保键的唯一性的应用场景非常有用。
  3. 高效的插入和删除:由于std::map使用红黑树作为底层数据结构,插入和删除操作的平均时间复杂度为O(log N),其中N是std::map中元素的数量。
  4. 灵活性std::map提供了丰富的成员函数和操作,使得对键值对的访问、修改和查找操作非常方便。

缺点:

  1. 额外空间开销std::map使用红黑树作为底层数据结构,这需要额外的内存空间来存储树节点的指针和颜色信息。相比于其他数据结构,这可能导致更高的存储开销。
  2. 相对较慢的查找速度:虽然std::map中的查找操作仍然非常高效(平均时间复杂度为O(log N)),但相比于哈希表等数据结构,它的查找速度可能稍慢一些。
  3. 无法直接访问元素:与基于索引的容器(如std::vector)不同,std::map无法通过索引直接访问元素,而是通过键来进行访问。这在某些场景下可能会增加编码的复杂度。

综上所述,std::map适合于需要有序性和唯一键的场景,以及对插入和删除操作的性能要求较高的场景。但需要注意的是,对于大规模数据集和需要频繁的随机访问操作的场景,可能有更适合的数据结构选择。在选择使用std::map时,需要综合考虑具体的应用需求和性能要求。

你可能感兴趣的:(C,++语法知识,c++,rpc,开发语言)