首页 > 后端开发 > C++ > 正文

怎样使用C++标准库容器 vector map set核心操作

P粉602998670
发布: 2025-08-11 15:33:02
原创
740人浏览过

c++++标准库中的vector、map和set分别适用于动态数组、键值对存储和唯一元素集合场景。1. vector支持动态大小数组,常用操作包括push_back、emplace_back添加元素,at或下标访问,erase删除元素,reserve预分配内存而不改变大小,resize则改变元素数量并初始化;2. map基于红黑树实现,键唯一且有序,通过insert、emplace插入,find查找,erase删除,支持自定义排序如使用函数对象或lambda表达式;3. set存储唯一有序元素,操作与map类似,插入重复元素会被忽略;4. 选择容器时,若需随机访问和尾部操作选vector,若需键值对且有序选map,若需快速查找唯一元素且有序选set;5. 对性能要求高且无需排序时,可选用unordered_map或unordered_set,其基于哈希表,平均查找时间复杂度为o(1);6. 自定义排序需满足严格弱排序规则,可通过函数对象、lambda或函数指针实现。正确选择容器能显著提升程序效率和代码质量。

怎样使用C++标准库容器 vector map set核心操作

C++标准库容器

vector
登录后复制
map
登录后复制
set
登录后复制
提供了高效的数据存储和管理方式。掌握它们的核心操作,能显著提升C++编程效率和代码质量。下面我们深入探讨这些容器的使用方法。

解决方案

vector
登录后复制
map
登录后复制
set
登录后复制
是C++ STL (Standard Template Library) 中最常用的容器。它们分别代表了动态数组、键值对映射和集合这三种基本的数据结构。

立即学习C++免费学习笔记(深入)”;

  • vector
    登录后复制
    : 动态数组,可以动态地调整大小。
  • map
    登录后复制
    : 存储键值对,其中键是唯一的,并且按照某种顺序排列
  • set
    登录后复制
    : 存储唯一的元素,并且按照某种顺序排列。

以下是一些核心操作的示例和解释:

vector
登录后复制

  • 包含头文件:

    #include <vector>
    登录后复制

  • 创建

    vector
    登录后复制
    :

    std::vector<int> myVector; // 创建一个存储int类型的空vector
    std::vector<int> myVector2(10); // 创建一个包含10个int元素的vector,默认值为0
    std::vector<int> myVector3(10, 5); // 创建一个包含10个int元素的vector,每个元素的值为5
    std::vector<int> myVector4 = {1, 2, 3, 4, 5}; // 使用初始化列表
    登录后复制
  • 添加元素:

    myVector.push_back(10); // 在vector末尾添加一个元素
    myVector.emplace_back(20); // 类似于push_back,但是更高效,尤其是在添加对象时
    登录后复制
  • 访问元素:

    int firstElement = myVector[0]; // 使用下标访问(不进行边界检查)
    int secondElement = myVector.at(1); // 使用at()访问(进行边界检查,越界会抛出异常)
    int lastElement = myVector.back(); // 访问最后一个元素
    int* dataPtr = myVector.data(); // 获取指向内部数组的指针(C++11)
    登录后复制
  • 删除元素:

    智标领航
    智标领航

    专注招投标业务流程的AI助手,智能、高效、精准、易用!

    智标领航 117
    查看详情 智标领航
    myVector.pop_back(); // 删除最后一个元素
    myVector.erase(myVector.begin() + 2); // 删除索引为2的元素
    myVector.erase(myVector.begin(), myVector.begin() + 3); // 删除一个范围内的元素
    myVector.clear(); // 删除所有元素
    登录后复制
  • 大小和容量:

    size_t size = myVector.size(); // 获取vector中元素的数量
    size_t capacity = myVector.capacity(); // 获取vector分配的内存大小
    myVector.reserve(100); // 预分配100个元素的空间,避免频繁重新分配
    myVector.shrink_to_fit(); // 释放多余的内存空间(C++11)
    登录后复制
  • 迭代:

    for (size_t i = 0; i < myVector.size(); ++i) {
        std::cout << myVector[i] << " ";
    }
    
    for (auto it = myVector.begin(); it != myVector.end(); ++it) {
        std::cout << *it << " ";
    }
    
    for (int element : myVector) { // 范围for循环 (C++11)
        std::cout << element << " ";
    }
    登录后复制

map
登录后复制

  • 包含头文件:

    #include <map>
    登录后复制

  • 创建

    map
    登录后复制
    :

    std::map<std::string, int> myMap; // 创建一个键为string,值为int的map
    std::map<int, std::string, std::greater<int>> myMap2; // 创建一个键为int,值为string的map,并使用std::greater<int>排序(降序)
    登录后复制
  • 插入元素:

    myMap["apple"] = 1; // 使用下标插入
    myMap.insert({"banana", 2}); // 使用insert插入pair
    myMap.emplace("cherry", 3); // 使用emplace直接构造元素(更高效)
    登录后复制
  • 访问元素:

    int appleCount = myMap["apple"]; // 使用下标访问(如果键不存在,会插入一个默认值)
    int bananaCount = myMap.at("banana"); // 使用at()访问(如果键不存在,会抛出异常)
    登录后复制
  • 查找元素:

    auto it = myMap.find("apple");
    if (it != myMap.end()) {
        std::cout << "Found apple: " << it->second << std::endl;
    } else {
        std::cout << "Apple not found" << std::endl;
    }
    登录后复制
  • 删除元素:

    myMap.erase("apple"); // 删除键为"apple"的元素
    myMap.erase(myMap.find("banana")); // 使用迭代器删除元素
    myMap.clear(); // 删除所有元素
    登录后复制
  • 大小:

    size_t size = myMap.size(); // 获取map中元素的数量
    登录后复制
  • 迭代:

    for (auto it = myMap.begin(); it != myMap.end(); ++it) {
        std::cout << it->first << ": " << it->second << std::endl;
    }
    
    for (auto const& [key, val] : myMap) { // 范围for循环 (C++17)
        std::cout << key << ": " << val << std::endl;
    }
    登录后复制

set
登录后复制

  • 包含头文件:

    #include <set>
    登录后复制

  • 创建

    set
    登录后复制
    :

    std::set<int> mySet; // 创建一个存储int类型的set
    std::set<int, std::greater<int>> mySet2; // 创建一个存储int类型的set,并使用std::greater<int>排序(降序)
    登录后复制
  • 插入元素:

    mySet.insert(10);
    mySet.insert(20);
    mySet.insert(10); // 插入重复元素会被忽略
    mySet.emplace(30); // 使用emplace直接构造元素(更高效)
    登录后复制
  • 查找元素:

    auto it = mySet.find(20);
    if (it != mySet.end()) {
        std::cout << "Found 20" << std::endl;
    } else {
        std::cout << "20 not found" << std::endl;
    }
    登录后复制
  • 删除元素:

    mySet.erase(20); // 删除值为20的元素
    mySet.erase(mySet.find(30)); // 使用迭代器删除元素
    mySet.clear(); // 删除所有元素
    登录后复制
  • 大小:

    size_t size = mySet.size(); // 获取set中元素的数量
    登录后复制
  • 迭代:

    for (auto it = mySet.begin(); it != mySet.end(); ++it) {
        std::cout << *it << " ";
    }
    
    for (int element : mySet) { // 范围for循环 (C++11)
        std::cout << element << " ";
    }
    登录后复制

如何选择合适的C++容器:vector, map, set?

选择容器取决于你的具体需求。

  • vector
    登录后复制
    : 当你需要一个动态数组,并且需要频繁地在末尾添加或删除元素时,
    vector
    登录后复制
    是一个很好的选择。它提供快速的随机访问,但在中间插入或删除元素效率较低。

  • map
    登录后复制
    : 当你需要存储键值对,并且需要根据键快速查找值时,
    map
    登录后复制
    是理想的选择。
    map
    登录后复制
    内部使用红黑树实现,保证了插入、删除和查找操作的对数时间复杂度。

  • set
    登录后复制
    : 当你需要存储唯一的元素,并且需要快速查找元素是否存在时,
    set
    登录后复制
    是合适的选择。
    set
    登录后复制
    也使用红黑树实现,保证了插入、删除和查找操作的对数时间复杂度。另外,
    set
    登录后复制
    会自动排序元素。

如果需要保持插入顺序,

std::unordered_map
登录后复制
std::unordered_set
登录后复制
(基于哈希表) 提供了平均常数时间的查找,但牺牲了排序特性。

vector
登录后复制
reserve
登录后复制
resize
登录后复制
有什么区别?何时使用?

reserve
登录后复制
resize
登录后复制
都是
vector
登录后复制
中用于管理内存的函数,但它们的作用不同。

  • reserve(n)
    登录后复制
    : 预分配至少能容纳
    n
    登录后复制
    个元素的内存空间,但不会改变
    vector
    登录后复制
    的大小(
    size
    登录后复制
    )。这意味着
    vector
    登录后复制
    仍然是空的,不能通过下标访问这些预留的空间。
    reserve
    登录后复制
    主要用于避免
    vector
    登录后复制
    在添加元素时频繁地重新分配内存,从而提高性能。

  • resize(n)
    登录后复制
    : 改变
    vector
    登录后复制
    的大小(
    size
    登录后复制
    )为
    n
    登录后复制
    。如果
    n
    登录后复制
    小于当前大小,则删除多余的元素;如果
    n
    登录后复制
    大于当前大小,则添加新的元素,并使用默认值初始化。
    resize
    登录后复制
    会直接影响
    vector
    登录后复制
    中元素的数量。

何时使用?

  • 当你预先知道
    vector
    登录后复制
    需要存储多少个元素,但还没有元素数据时,使用
    reserve
    登录后复制
    可以避免不必要的内存重新分配。
  • 当你需要改变
    vector
    登录后复制
    中元素的数量,并且需要初始化新增的元素时,使用
    resize
    登录后复制

举例:

std::vector<int> myVector;
myVector.reserve(100); // 预分配100个int的空间,size仍然为0

for (int i = 0; i < 100; ++i) {
    myVector.push_back(i); // 添加元素,不会触发重新分配
}

std::vector<int> myVector2;
myVector2.resize(100); // size变为100,所有元素初始化为0

for (int i = 0; i < myVector2.size(); ++i) {
    myVector2[i] = i; // 可以直接通过下标访问元素
}
登录后复制

map
登录后复制
unordered_map
登录后复制
的区别?如何选择?

map
登录后复制
unordered_map
登录后复制
都是C++中用于存储键值对的容器,但它们的实现方式和性能特点不同。

  • map
    登录后复制
    : 基于红黑树实现,键是有序的。插入、删除和查找操作的时间复杂度为O(log n),其中n是
    map
    登录后复制
    中元素的数量。
    map
    登录后复制
    的优点是键是有序的,可以方便地进行范围查找。

  • unordered_map
    登录后复制
    : 基于哈希表实现,键是无序的。平均情况下,插入、删除和查找操作的时间复杂度为O(1),但在最坏情况下可能退化为O(n)。
    unordered_map
    登录后复制
    的优点是平均查找速度快,但缺点是键是无序的,且需要额外的内存空间来存储哈希表。

如何选择?

  • 如果你需要键是有序的,或者需要进行范围查找,那么选择
    map
    登录后复制
  • 如果你对键的顺序没有要求,并且需要尽可能快的查找速度,那么选择
    unordered_map
    登录后复制
  • 如果数据量很小,
    map
    登录后复制
    unordered_map
    登录后复制
    的性能差异可能不明显。
  • unordered_map
    登录后复制
    对哈希函数的要求较高,需要选择合适的哈希函数来避免哈希冲突,从而保证性能。

总的来说,

unordered_map
登录后复制
在大多数情况下比
map
登录后复制
更快,但
map
登录后复制
在某些特定场景下仍然有其优势。选择哪个容器取决于你的具体需求。

set
登录后复制
unordered_set
登录后复制
的区别?如何选择?

set
登录后复制
unordered_set
登录后复制
类似于
map
登录后复制
unordered_map
登录后复制
, 它们都是存储唯一元素的容器,区别在于底层实现和性能特性。

  • set
    登录后复制
    : 基于红黑树实现,元素是有序的。插入、删除和查找操作的时间复杂度为O(log n)。

  • unordered_set
    登录后复制
    : 基于哈希表实现,元素是无序的。平均情况下,插入、删除和查找操作的时间复杂度为O(1),最坏情况下可能退化为O(n)。

如何选择?

  • 如果你需要元素是有序的,或者需要进行范围查找,那么选择
    set
    登录后复制
  • 如果你对元素的顺序没有要求,并且需要尽可能快的查找速度,那么选择
    unordered_set
    登录后复制

选择原则与

map
登录后复制
unordered_map
登录后复制
类似, 考虑是否需要排序以及对查找速度的要求。

如何自定义排序规则用于
set
登录后复制
map
登录后复制

可以通过以下几种方式自定义排序规则:

  1. 函数对象 (Functor): 创建一个类,重载

    operator()
    登录后复制
    ,实现自定义的比较逻辑。

    struct MyComparator {
        bool operator()(const int& a, const int& b) const {
            return a > b; // 降序排列
        }
    };
    
    std::set<int, MyComparator> mySet;
    std::map<int, std::string, MyComparator> myMap;
    登录后复制
  2. Lambda 表达式 (C++11): 使用 lambda 表达式定义比较函数。

    auto myComparator = [](const int& a, const int& b) {
        return a > b; // 降序排列
    };
    
    std::set<int, decltype(myComparator)> mySet(myComparator);
    std::map<int, std::string, decltype(myComparator)> myMap(myComparator);
    登录后复制
  3. 函数指针: 定义一个函数,然后将函数指针传递给

    set
    登录后复制
    map
    登录后复制
    。 (不常用,因为不如函数对象或 lambda 灵活)

无论使用哪种方式,比较函数都必须满足严格弱排序 (strict weak ordering) 的要求。这意味着对于任意元素 a, b, c:

  • comp(a, a)
    登录后复制
    必须为
    false
    登录后复制
    (非自反性)
  • 如果
    comp(a, b)
    登录后复制
    true
    登录后复制
    ,则
    comp(b, a)
    登录后复制
    必须为
    false
    登录后复制
    (反对称性)
  • 如果
    comp(a, b)
    登录后复制
    true
    登录后复制
    comp(b, c)
    登录后复制
    true
    登录后复制
    ,则
    comp(a, c)
    登录后复制
    必须为
    true
    登录后复制
    (传递性)

不满足严格弱排序会导致未定义行为。

以上就是怎样使用C++标准库容器 vector map set核心操作的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号