文章目录

C++ STL 容器:vector、list、map 的使用

发布于 2026-04-18 19:24:25 · 浏览 13 次 · 评论 0 条

C++ STL 容器:vector、list、map 的使用

C++ 标准模板库(STL)提供了三种最核心的容器:vector(动态数组)、list(双向链表)和 map(映射)。掌握它们的使用是编写高效 C++ 代码的基础。以下指南将直接展示如何在代码中应用它们,涵盖定义、增删改查及适用场景。


1. 使用 vector(动态数组)

vector 是一个能够自动扩展大小的数组。它的内存是连续的,支持通过下标快速访问,非常适合元素数量变化较大但主要进行尾部操作的场景。

1.1 准备工作

包含 <vector> 头文件以使用该容器。

#include <vector>
#include <iostream>

int main() {
    // 代码示例将在此处编写
    return 0;
}

1.2 创建与初始化

定义 一个存储整数类型的 vector。

std::vector<int> numbers; // 创建一个空 vector
std::vector<int> scores(10, 0); // 创建包含10个0的 vector

1.3 添加与访问元素

调用 push_back 方法在数组末尾添加元素。

numbers.push_back(5);
numbers.push_back(10);
numbers.push_back(15);

使用 下标运算符 []at() 方法读取元素。

int first = numbers[0]; // 获取第一个元素(5)
int second = numbers.at(1); // 获取第二个元素(10),会进行边界检查

遍历 容器打印所有元素。

for (size_t i = 0; i < numbers.size(); ++i) {
    std::cout << numbers[i] << " ";
}
// 输出: 5 10 15

1.4 删除与修改

修改 指定位置的元素。

numbers[1] = 20; // 将第二个元素修改为 20

调用 pop_back 移除最后一个元素。

numbers.pop_back(); // 移除 15

注意vector 在中间插入或删除元素效率较低,因为需要移动后续所有元素。若需要在中间频繁操作,请考虑使用 list


2. 使用 list(双向链表)

list 由节点组成,每个节点存储数据并指向前驱和后继。它在任何位置的插入和删除操作都非常快,时间复杂度为 $O(1)$,但不支持随机访问(不能直接用 numbers[2] 访问)。

2.1 准备工作

包含 <list> 头文件。

#include <list>
#include <iostream>

2.2 创建与初始化

定义 一个存储字符串的 list。

std::list<std::string> tasks;

2.3 添加元素

调用 push_backpush_front 在两端添加元素。

tasks.push_back("Coding");
tasks.push_front("Meeting");
tasks.push_back("Debugging");

此时链表顺序为:Meeting -> Coding -> Debugging

2.4 插入与删除(核心优势)

获取 指向第二个元素的迭代器。

std::list<std::string>::iterator it = tasks.begin();
std::advance(it, 1); // 将迭代器向后移动一位,指向 "Coding"

调用 insert 在迭代器位置插入元素。

tasks.insert(it, "Refactoring"); 
// 顺序变为: Meeting -> Refactoring -> Coding -> Debugging

调用 erase 删除迭代器指向的元素。

tasks.erase(it); // 删除原迭代器指向的 "Coding"
// 顺序变为: Meeting -> Refactoring -> Debugging

2.5 遍历

由于不支持随机访问,使用 迭代器或范围 for 循环进行遍历。

for (const auto& task : tasks) {
    std::cout << task << " -> ";
}
// 输出: Meeting -> Refactoring -> Debugging ->

3. 使用 map(键值对映射)

map 存储的是“键值对”。每个键(Key)都是唯一的,对应一个值(Value)。map 内部通常由红黑树实现,会根据键自动排序,查找效率很高,时间复杂度为 $O(\log n)$。

3.1 准备工作

包含 <map> 头文件。

#include <map>
#include <string>

3.2 创建与初始化

定义 一个键为 std::string,值为 int 的 map(例如存储学生分数)。

std::map<std::string, int> scores;

3.3 插入与修改

使用 下标运算符 [] 插入或修改数据。如果键不存在,会自动创建;如果存在,会覆盖旧值。

scores["Alice"] = 90;
scores["Bob"] = 85;
scores["Charlie"] = 95;

// 修改 Alice 的分数
scores["Alice"] = 88;

或者,调用 insert 方法插入。注意,如果键已存在,insert 不会修改现有值。

scores.insert(std::make_pair("David", 80));

3.4 查找与访问

使用 find 方法查找特定键是否存在。该方法返回一个迭代器。

auto search = scores.find("Bob");
if (search != scores.end()) {
    std::cout << "Bob's score: " << search->second << std::endl;
} else {
    std::cout << "Bob not found" << std::endl;
}

3.5 遍历

map 会按照键的字典序自动排序(A-Z)。

for (const auto& pair : scores) {
    std::cout << pair.first << ": " << pair.second << std::endl;
}
// 输出顺序可能是: Alice, Bob, Charlie, David

4. 容器选择对比表

在实际开发中,根据操作需求选择合适的容器至关重要。下表总结了三者的核心区别。

特性 vector (动态数组) list (双向链表) map (映射)
内存结构 连续内存 非连续内存(节点) 红黑树结构(节点)
随机访问 支持 ($O(1)$) 不支持 不支持(仅支持通过键访问)
头部/中间插入 慢 ($O(n)$) 快 ($O(1)$) 快 ($O(\log n)$)
尾部插入 快 ($O(1)$,均摊) 快 ($O(1)$) N/A
查找效率 慢(需遍历,除非有序) 慢(需遍历) 快 ($O(\log n)$)
主要用途 存储元素个数可变,主要进行尾部操作 频繁在任意位置插入/删除 需要根据键快速查找值,或需要自动排序

总结选择逻辑

  1. 需要通过下标(如 arr[i])快速访问?选择 vector
  2. 需要频繁在列表中间插入或删除数据,且很少随机访问?选择 list
  3. 需要存储“键值对”关系,并需要通过键快速找到值?选择 map
// 示例:综合使用
std::vector<int> dataStore; // 用于存储大量数据流水
std::list<int> activeTasks; // 用于管理需要动态移除的任务ID
std::map<int, std::string> idToName; // 用于ID与名字的快速对应查询

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文