使用 C++ 中的 STL 组件

C++C++Beginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,你将学习如何使用 C++ 标准模板库(STL)中的各种组件来创建和操作数据结构,例如向量(vector)、列表(list)、映射(map)、集合(set)等。你将探索这些 STL 容器的基本操作,包括添加、删除和遍历元素。此外,你还将了解如何利用 STL 算法对这些容器中的数据进行排序、搜索和处理。通过本实验的学习,你将深入理解如何利用 C++ STL 的强大功能和灵活性来构建高效且健壮的应用程序。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL cpp(("`C++`")) -.-> cpp/BasicsGroup(["`Basics`"]) cpp(("`C++`")) -.-> cpp/ControlFlowGroup(["`Control Flow`"]) cpp(("`C++`")) -.-> cpp/AdvancedConceptsGroup(["`Advanced Concepts`"]) cpp(("`C++`")) -.-> cpp/StandardLibraryGroup(["`Standard Library`"]) cpp/BasicsGroup -.-> cpp/data_types("`Data Types`") cpp/BasicsGroup -.-> cpp/arrays("`Arrays`") cpp/ControlFlowGroup -.-> cpp/for_loop("`For Loop`") cpp/AdvancedConceptsGroup -.-> cpp/exceptions("`Exceptions`") cpp/StandardLibraryGroup -.-> cpp/string_manipulation("`String Manipulation`") cpp/StandardLibraryGroup -.-> cpp/standard_containers("`Standard Containers`") subgraph Lab Skills cpp/data_types -.-> lab-446087{{"`使用 C++ 中的 STL 组件`"}} cpp/arrays -.-> lab-446087{{"`使用 C++ 中的 STL 组件`"}} cpp/for_loop -.-> lab-446087{{"`使用 C++ 中的 STL 组件`"}} cpp/exceptions -.-> lab-446087{{"`使用 C++ 中的 STL 组件`"}} cpp/string_manipulation -.-> lab-446087{{"`使用 C++ 中的 STL 组件`"}} cpp/standard_containers -.-> lab-446087{{"`使用 C++ 中的 STL 组件`"}} end

创建和操作 Vector 容器

在本步骤中,你将学习 C++ 标准模板库(STL)中的 vector 容器,它是一种可以动态调整大小的数组。Vector 非常适合用于存储和操作元素集合。

首先,打开 WebIDE 并在 ~/project 目录下创建一个名为 vector_demo.cpp 的新文件。我们将逐步探索 vector 的基本操作。

touch ~/project/vector_demo.cpp

将以下代码添加到 vector_demo.cpp 文件中:

#include <iostream>
#include <vector>

int main() {
    // 创建一个空的整数 vector
    std::vector<int> numbers;

    // 使用 push_back() 向 vector 添加元素
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);

    // 打印 vector 的大小
    std::cout << "Vector size: " << numbers.size() << std::endl;

    // 使用索引访问元素
    std::cout << "First element: " << numbers[0] << std::endl;
    std::cout << "Second element: " << numbers[1] << std::endl;

    // 使用范围-based for 循环遍历 vector
    std::cout << "All elements: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 移除最后一个元素
    numbers.pop_back();

    // 检查移除元素后的新大小
    std::cout << "Vector size after pop_back(): " << numbers.size() << std::endl;

    return 0;
}

编译并运行程序:

g++ vector_demo.cpp -o vector_demo
./vector_demo

示例输出:

Vector size: 3
First element: 10
Second element: 20
All elements: 10 20 30
Vector size after pop_back(): 2

关于 vector 的关键点:

  • 使用 #include <vector> 引入 vector 库
  • std::vector<type> 创建一个特定类型的 vector
  • push_back() 向 vector 末尾添加元素
  • size() 返回元素的数量
  • 使用索引 [] 访问元素
  • pop_back() 移除最后一个元素
  • 范围-based for 循环是遍历 vector 的简便方式

使用 List 进行链表操作

在本步骤中,你将学习 C++ STL 中的 list 容器,它实现了双向链表。List 提供了在任何位置高效插入和删除元素的操作。

打开 WebIDE 并在 ~/project 目录下创建一个名为 list_demo.cpp 的新文件:

touch ~/project/list_demo.cpp

将以下代码添加到 list_demo.cpp 文件中:

#include <iostream>
#include <list>

int main() {
    // 创建一个空的整数 list
    std::list<int> numbers;

    // 向 list 添加元素
    numbers.push_back(10);    // 添加到末尾
    numbers.push_front(5);    // 添加到开头
    numbers.push_back(20);

    // 打印 list 的大小
    std::cout << "List size: " << numbers.size() << std::endl;

    // 遍历 list
    std::cout << "List elements: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 移除元素
    numbers.pop_front();  // 移除第一个元素
    numbers.pop_back();   // 移除最后一个元素

    // 在特定位置插入元素
    auto it = numbers.begin();
    numbers.insert(it, 15);

    // 打印更新后的 list
    std::cout << "Updated list: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 检查 list 是否为空
    std::cout << "Is list empty? "
              << (numbers.empty() ? "Yes" : "No") << std::endl;

    return 0;
}

编译并运行程序:

g++ list_demo.cpp -o list_demo
./list_demo

示例输出:

List size: 3
List elements: 5 10 20
Updated list: 15 10
Is list empty? No

关于 list 的关键点:

  • 使用 #include <list> 引入 list 库
  • push_back() 向末尾添加元素
  • push_front() 向开头添加元素
  • pop_front()pop_back() 移除元素
  • insert() 允许在特定位置插入元素
  • begin() 返回指向第一个元素的迭代器
  • empty() 检查 list 是否为空

使用 Map 实现键值对

在本步骤中,你将学习 C++ STL 中的 map 容器,它以排序且唯一的键顺序存储键值对。Map 非常适合用于创建字典或关联数组。

打开 WebIDE 并在 ~/project 目录下创建一个名为 map_demo.cpp 的新文件:

touch ~/project/map_demo.cpp

将以下代码添加到 map_demo.cpp 文件中:

#include <iostream>
#include <map>
#include <string>

int main() {
    // 创建一个 map 来存储学生姓名和年龄
    std::map<std::string, int> students;

    // 插入键值对
    students["Alice"] = 20;
    students["Bob"] = 22;
    students["Charlie"] = 21;

    // 使用键访问值
    std::cout << "Alice's age: " << students["Alice"] << std::endl;

    // 检查键是否存在
    if (students.count("David") == 0) {
        std::cout << "David is not in the map" << std::endl;
    }

    // 遍历 map
    std::cout << "All students:" << std::endl;
    for (const auto& student : students) {
        std::cout << student.first << ": " << student.second << std::endl;
    }

    // 移除一个键值对
    students.erase("Bob");

    // 检查 map 的大小
    std::cout << "Number of students: " << students.size() << std::endl;

    return 0;
}

编译并运行程序:

g++ map_demo.cpp -o map_demo
./map_demo

示例输出:

Alice's age: 20
David is not in the map
All students:
Alice: 20
Bob: 22
Charlie: 21
Number of students: 2

关于 map 的关键点:

  • 使用 #include <map> 引入 map 库
  • map<KeyType, ValueType> 创建一个指定键和值类型的 map
  • 使用方括号 [] 访问值
  • count() 检查键是否存在
  • 使用范围-based for 循环遍历 map
  • erase() 移除一个键值对
  • size() 返回元素的数量

使用 Set 存储唯一元素

在本步骤中,你将学习 C++ STL 中的 set 容器,它以排序顺序存储唯一元素。Set 会自动防止重复值,并按照特定顺序维护元素。

打开 WebIDE 并在 ~/project 目录下创建一个名为 set_demo.cpp 的新文件:

touch ~/project/set_demo.cpp

将以下代码添加到 set_demo.cpp 文件中:

#include <iostream>
#include <set>

int main() {
    // 创建一个整数 set
    std::set<int> numbers;

    // 插入元素
    numbers.insert(10);
    numbers.insert(20);
    numbers.insert(30);
    numbers.insert(10);  // 重复值,不会被添加

    // 打印 set 的大小
    std::cout << "Set size: " << numbers.size() << std::endl;

    // 遍历 set
    std::cout << "Set elements: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 检查元素是否存在
    if (numbers.count(20) > 0) {
        std::cout << "20 is in the set" << std::endl;
    }

    // 移除一个元素
    numbers.erase(20);

    // 检查移除后的 set 大小
    std::cout << "Set size after removal: " << numbers.size() << std::endl;

    // 清空 set
    numbers.clear();

    // 检查 set 是否为空
    std::cout << "Is set empty? "
              << (numbers.empty() ? "Yes" : "No") << std::endl;

    return 0;
}

编译并运行程序:

g++ set_demo.cpp -o set_demo
./set_demo

示例输出:

Set size: 3
Set elements: 10 20 30
20 is in the set
Set size after removal: 2
Is set empty? Yes

关于 set 的关键点:

  • 使用 #include <set> 引入 set 库
  • set<type> 创建一个存储唯一元素的 set
  • insert() 添加元素(重复值会被忽略)
  • count() 检查元素是否存在
  • erase() 移除一个元素
  • clear() 移除所有元素
  • empty() 检查 set 是否为空
  • 元素会自动排序

使用 STL sort 算法对元素排序

在本步骤中,你将学习如何使用 STL 的 sort 算法对元素进行升序或降序排列。<algorithm> 库为各种容器提供了强大的排序功能。

打开 WebIDE 并在 ~/project 目录下创建一个名为 sort_demo.cpp 的新文件:

touch ~/project/sort_demo.cpp

将以下代码添加到 sort_demo.cpp 文件中:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建一个整数 vector
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3};

    // 打印原始 vector
    std::cout << "Original vector: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 对 vector 进行升序排序
    std::sort(numbers.begin(), numbers.end());

    // 打印排序后的 vector
    std::cout << "Sorted vector (ascending): ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 对 vector 进行降序排序
    std::sort(numbers.begin(), numbers.end(), std::greater<int>());

    // 打印降序排序后的 vector
    std::cout << "Sorted vector (descending): ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

编译并运行程序:

g++ sort_demo.cpp -o sort_demo
./sort_demo

示例输出:

Original vector: 5 2 8 1 9 3
Sorted vector (ascending): 1 2 3 5 8 9
Sorted vector (descending): 9 8 5 3 2 1

关于 STL sort 的关键点:

  • 引入 <algorithm> 库以使用排序功能
  • std::sort() 适用于多种容器
  • 默认排序为升序
  • std::greater<type>() 用于降序排序
  • 排序是原地进行的,会修改原始容器
  • 高效适用于不同类型的容器

使用 STL 算法查找元素

在本步骤中,你将学习如何使用 STL 算法在容器中查找和搜索元素。<algorithm> 库提供了强大的函数来搜索和定位元素。

打开 WebIDE 并在 ~/project 目录下创建一个名为 find_demo.cpp 的新文件:

touch ~/project/find_demo.cpp

将以下代码添加到 find_demo.cpp 文件中:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建一个整数 vector
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3, 8};

    // 查找特定元素的首次出现
    auto it = std::find(numbers.begin(), numbers.end(), 8);
    if (it != numbers.end()) {
        std::cout << "First occurrence of 8 at index: "
                  << std::distance(numbers.begin(), it) << std::endl;
    }

    // 计算元素的出现次数
    int count = std::count(numbers.begin(), numbers.end(), 8);
    std::cout << "Number of 8s in the vector: " << count << std::endl;

    // 查找是否有元素大于 6
    bool has_large_element = std::any_of(numbers.begin(), numbers.end(),
        [](int n) { return n > 6; });
    std::cout << "Vector has element > 6: "
              << (has_large_element ? "Yes" : "No") << std::endl;

    // 查找最小和最大元素
    auto min_it = std::min_element(numbers.begin(), numbers.end());
    auto max_it = std::max_element(numbers.begin(), numbers.end());

    std::cout << "Minimum element: " << *min_it << std::endl;
    std::cout << "Maximum element: " << *max_it << std::endl;

    return 0;
}

编译并运行程序:

g++ find_demo.cpp -o find_demo
./find_demo

示例输出:

First occurrence of 8 at index: 2
Number of 8s in the vector: 2
Vector has element > 6: Yes
Minimum element: 1
Maximum element: 9

关于 STL 搜索算法的关键点:

  • std::find() 查找元素的首次出现
  • std::count() 计算元素的出现次数
  • std::any_of() 检查是否有元素满足条件
  • std::min_element()std::max_element() 查找极值
  • 可以使用 Lambda 函数定义自定义搜索条件
  • 返回的迭代器指向找到的元素

遍历容器

在本步骤中,你将学习使用不同的遍历技术来遍历 STL 容器的多种方法。我们将探索基于范围的 for 循环、迭代器以及传统的基于索引的遍历。

打开 WebIDE 并在 ~/project 目录下创建一个名为 iteration_demo.cpp 的新文件:

touch ~/project/iteration_demo.cpp

将以下代码添加到 iteration_demo.cpp 文件中:

#include <iostream>
#include <vector>
#include <list>
#include <map>

int main() {
    // Vector 遍历
    std::vector<int> numbers = {10, 20, 30, 40, 50};

    // 方法 1: 基于范围的 for 循环(最现代且可读性高)
    std::cout << "Vector iteration (range-based for):" << std::endl;
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 方法 2: 基于迭代器的遍历
    std::cout << "Vector iteration (iterators):" << std::endl;
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 方法 3: 基于索引的遍历
    std::cout << "Vector iteration (index-based):" << std::endl;
    for (size_t i = 0; i < numbers.size(); ++i) {
        std::cout << numbers[i] << " ";
    }
    std::cout << std::endl;

    // Map 遍历
    std::map<std::string, int> ages = {
        {"Alice", 25},
        {"Bob", 30},
        {"Charlie", 35}
    };

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

    return 0;
}

编译并运行程序:

g++ iteration_demo.cpp -o iteration_demo
./iteration_demo

示例输出:

Vector iteration (range-based for):
10 20 30 40 50
Vector iteration (iterators):
10 20 30 40 50
Vector iteration (index-based):
10 20 30 40 50
Map iteration:
Alice: 25
Bob: 30
Charlie: 35

关于容器遍历的关键点:

  • 基于范围的 for 循环是最现代且可读性高的方式
  • 迭代器提供了对容器遍历的细粒度控制
  • 基于索引的遍历适用于支持随机访问的容器
  • auto 关键字有助于类型推断
  • 不同的容器支持不同的遍历方法

使用 STL 的 Stack 和 Queue

在本步骤中,你将学习两个重要的 STL 容器适配器:stack 和 queue。这些容器为后进先出(LIFO)和先进先出(FIFO)的数据管理提供了专门的操作。

打开 WebIDE 并在 ~/project 目录下创建一个名为 stack_queue_demo.cpp 的新文件:

touch ~/project/stack_queue_demo.cpp

将以下代码添加到 stack_queue_demo.cpp 文件中:

#include <iostream>
#include <stack>
#include <queue>

int main() {
    // Stack 演示
    std::stack<int> myStack;

    // 向 stack 中添加元素
    myStack.push(10);
    myStack.push(20);
    myStack.push(30);

    std::cout << "Stack operations:" << std::endl;
    std::cout << "Top element: " << myStack.top() << std::endl;

    // 移除顶部元素
    myStack.pop();
    std::cout << "Top element after pop: " << myStack.top() << std::endl;
    std::cout << "Stack size: " << myStack.size() << std::endl;

    // Queue 演示
    std::queue<std::string> myQueue;

    // 向 queue 中添加元素
    myQueue.push("Alice");
    myQueue.push("Bob");
    myQueue.push("Charlie");

    std::cout << "\nQueue operations:" << std::endl;
    std::cout << "Front element: " << myQueue.front() << std::endl;
    std::cout << "Back element: " << myQueue.back() << std::endl;

    // 移除队首元素
    myQueue.pop();
    std::cout << "Front element after pop: " << myQueue.front() << std::endl;
    std::cout << "Queue size: " << myQueue.size() << std::endl;

    return 0;
}

编译并运行程序:

g++ stack_queue_demo.cpp -o stack_queue_demo
./stack_queue_demo

示例输出:

Stack operations:
Top element: 30
Top element after pop: 20
Stack size: 2

Queue operations:
Front element: Alice
Back element: Charlie
Front element after pop: Bob
Queue size: 2

关于 stack 和 queue 的关键点:

  • Stack(LIFO - 后进先出)
    • push() 向顶部添加元素
    • pop() 移除顶部元素
    • top() 返回顶部元素
  • Queue(FIFO - 先进先出)
    • push() 向队尾添加元素
    • pop() 移除队首元素
    • front() 返回队首元素
    • back() 返回队尾元素
  • 两者都有 size() 方法用于检查元素数量
  • 引入 <stack><queue> 头文件

处理容器的异常安全性

在本步骤中,你将学习如何处理异常并确保 STL 容器的安全操作。异常处理有助于防止程序崩溃,并提供健壮的错误管理。

打开 WebIDE 并在 ~/project 目录下创建一个名为 exception_safety_demo.cpp 的新文件:

touch ~/project/exception_safety_demo.cpp

将以下代码添加到 exception_safety_demo.cpp 文件中:

#include <iostream>
#include <vector>
#include <stdexcept>

void demonstrateVectorSafety() {
    std::vector<int> numbers;

    try {
        // 尝试从空 vector 中访问元素
        std::cout << "Attempting to access element from empty vector:" << std::endl;
        numbers.at(0);  // 这将抛出 out_of_range 异常
    }
    catch (const std::out_of_range& e) {
        std::cout << "Out of Range Error: " << e.what() << std::endl;
    }

    // 安全的元素添加
    try {
        numbers.push_back(10);
        numbers.push_back(20);
        std::cout << "Vector size: " << numbers.size() << std::endl;

        // 安全的元素访问
        std::cout << "First element: " << numbers.at(0) << std::endl;
        std::cout << "Second element: " << numbers.at(1) << std::endl;
    }
    catch (const std::exception& e) {
        std::cout << "An error occurred: " << e.what() << std::endl;
    }
}

int main() {
    // 演示 vector 的异常安全性
    demonstrateVectorSafety();

    return 0;
}

编译并运行程序:

g++ exception_safety_demo.cpp -o exception_safety_demo
./exception_safety_demo

示例输出:

Attempting to access element from empty vector:
Out of Range Error: vector
Vector size: 2
First element: 10
Second element: 20

关于容器异常安全性的关键点:

  • 使用 try-catch 块处理潜在的异常
  • 当访问无效的 vector 元素时,会抛出 std::out_of_range 异常
  • at() 方法会进行边界检查,而 [] 操作符不会
  • 先捕获特定异常,再捕获更通用的异常
  • 始终处理潜在的异常以防止程序崩溃
  • 使用 <stdexcept> 中的标准异常类

总结

在本实验中,你学习了 C++ 标准模板库(STL)的各个组件及其高效使用方法。你首先探索了 vector 容器,它是一种可以动态调整大小的数组。你学习了如何添加和移除元素、使用索引访问元素,以及使用基于范围的 for 循环遍历 vector。

接下来,你深入研究了 list 容器,它是一种双向链表的实现。你了解了如何执行常见的链表操作,例如插入、删除和遍历元素。你还探索了 map 容器,它允许存储键值对,以及 set 容器,它存储唯一元素。此外,你学习了如何使用 STL 算法(如 sort 和 find)来操作和搜索这些容器中的元素。最后,你探索了 stack 和 queue 容器,并讨论了在使用 STL 组件时异常安全的重要性。

您可能感兴趣的其他 C++ 教程