Использование компонентов STL в C++

C++C++Beginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом лабораторном занятии вы узнаете, как использовать различные компоненты Стандартной Шаблонной Библиотеки (Standard Template Library, STL) языка C++ для создания и управления структурами данных, такими как векторы (vectors), списки (lists), ассоциативные массивы (maps), множества (sets) и другие. Вы изучите базовые операции с этими контейнерами STL, включая добавление, удаление и перебор элементов. Кроме того, вы узнаете, как использовать алгоритмы STL для сортировки, поиска и обработки данных в этих контейнерах. По завершении этого лабораторного занятия вы получите твердое понимание того, как использовать мощь и гибкость STL языка C++ для создания эффективных и надежных приложений.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL cpp(("C++")) -.-> cpp/AdvancedConceptsGroup(["Advanced Concepts"]) cpp(("C++")) -.-> cpp/StandardLibraryGroup(["Standard Library"]) cpp(("C++")) -.-> cpp/BasicsGroup(["Basics"]) cpp(("C++")) -.-> cpp/ControlFlowGroup(["Control Flow"]) 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{{"Использование компонентов STL в C++"}} cpp/arrays -.-> lab-446087{{"Использование компонентов STL в C++"}} cpp/for_loop -.-> lab-446087{{"Использование компонентов STL в C++"}} cpp/exceptions -.-> lab-446087{{"Использование компонентов STL в C++"}} cpp/string_manipulation -.-> lab-446087{{"Использование компонентов STL в C++"}} cpp/standard_containers -.-> lab-446087{{"Использование компонентов STL в C++"}} end

Создание и управление контейнером Vector

На этом этапе вы узнаете о контейнере vector из Стандартной Шаблонной Библиотеки (Standard Template Library, STL) языка C++. Это динамический массив, размер которого может увеличиваться и уменьшаться. Векторы (vectors) чрезвычайно полезны для хранения и управления коллекциями элементов.

Сначала откройте WebIDE и создайте новый файл с именем vector_demo.cpp в директории ~/project. Мы пошагово изучим базовые операции с векторами.

touch ~/project/vector_demo.cpp

Добавьте следующий код в файл vector_demo.cpp:

#include <iostream>
#include <vector>

int main() {
    // Create an empty vector of integers
    std::vector<int> numbers;

    // Add elements to the vector using push_back()
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);

    // Print the size of the vector
    std::cout << "Vector size: " << numbers.size() << std::endl;

    // Access elements using index
    std::cout << "First element: " << numbers[0] << std::endl;
    std::cout << "Second element: " << numbers[1] << std::endl;

    // Iterate through the vector using a range-based for loop
    std::cout << "All elements: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Remove the last element
    numbers.pop_back();

    // Check the new size after removing an element
    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

Основные моменты о векторах:

  • Используйте #include <vector> для включения библиотеки векторов
  • std::vector<type> создает вектор определенного типа
  • push_back() добавляет элементы в конец вектора
  • size() возвращает количество элементов
  • Обращайтесь к элементам с помощью индекса []
  • pop_back() удаляет последний элемент
  • Цикл for на основе диапазона (range-based for loop) - простой способ перебрать элементы вектора

Использование контейнера List для операций с двусвязным списком

На этом этапе вы узнаете о контейнере list из Стандартной Шаблонной Библиотеки (STL) языка C++, который реализует двусвязный список (doubly - linked list). Списки (lists) обеспечивают эффективные операции вставки и удаления элементов в любом положении контейнера.

Откройте WebIDE и создайте новый файл с именем list_demo.cpp в директории ~/project:

touch ~/project/list_demo.cpp

Добавьте следующий код в файл list_demo.cpp:

#include <iostream>
#include <list>

int main() {
    // Create an empty list of integers
    std::list<int> numbers;

    // Add elements to the list
    numbers.push_back(10);    // Add to the end
    numbers.push_front(5);    // Add to the beginning
    numbers.push_back(20);

    // Print the list size
    std::cout << "List size: " << numbers.size() << std::endl;

    // Iterate through the list
    std::cout << "List elements: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Remove elements
    numbers.pop_front();  // Remove first element
    numbers.pop_back();   // Remove last element

    // Insert an element at a specific position
    auto it = numbers.begin();
    numbers.insert(it, 15);

    // Print updated list
    std::cout << "Updated list: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Check if list is empty
    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

Основные моменты о списках:

  • Используйте #include <list> для включения библиотеки списков
  • push_back() добавляет элементы в конец списка
  • push_front() добавляет элементы в начало списка
  • pop_front() и pop_back() удаляют элементы
  • insert() позволяет добавлять элементы в определенную позицию
  • begin() возвращает итератор на первый элемент
  • empty() проверяет, является ли список пустым

Реализация пар ключ-значение с использованием контейнера Map

На этом этапе вы узнаете о контейнере map из Стандартной Шаблонной Библиотеки (STL) языка C++, который хранит пары ключ-значение в отсортированном порядке по уникальным ключам. Ассоциативные массивы (maps) полезны для создания словарей или ассоциативных массивов.

Откройте WebIDE и создайте новый файл с именем map_demo.cpp в директории ~/project:

touch ~/project/map_demo.cpp

Добавьте следующий код в файл map_demo.cpp:

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

int main() {
    // Create a map to store student names and their ages
    std::map<std::string, int> students;

    // Insert key-value pairs
    students["Alice"] = 20;
    students["Bob"] = 22;
    students["Charlie"] = 21;

    // Access values using keys
    std::cout << "Alice's age: " << students["Alice"] << std::endl;

    // Check if a key exists
    if (students.count("David") == 0) {
        std::cout << "David is not in the map" << std::endl;
    }

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

    // Remove a key-value pair
    students.erase("Bob");

    // Check the size of the 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

Основные моменты о ассоциативных массивах:

  • Используйте #include <map> для включения библиотеки ассоциативных массивов
  • map<KeyType, ValueType> создает ассоциативный массив с указанными типами ключей и значений
  • Обращайтесь к значениям с помощью квадратных скобок []
  • count() проверяет, существует ли ключ
  • Перебирайте элементы ассоциативных массивов с помощью цикла for на основе диапазона (range-based for loop)
  • erase() удаляет пару ключ-значение
  • size() возвращает количество элементов

Хранение уникальных элементов с использованием контейнера Set

На этом этапе вы узнаете о контейнере set из Стандартной Шаблонной Библиотеки (STL) языка C++, который хранит уникальные элементы в отсортированном порядке. Множества (sets) автоматически предотвращают дубликаты значений и поддерживают элементы в определенном порядке.

Откройте WebIDE и создайте новый файл с именем set_demo.cpp в директории ~/project:

touch ~/project/set_demo.cpp

Добавьте следующий код в файл set_demo.cpp:

#include <iostream>
#include <set>

int main() {
    // Create a set of integers
    std::set<int> numbers;

    // Insert elements
    numbers.insert(10);
    numbers.insert(20);
    numbers.insert(30);
    numbers.insert(10);  // Duplicate, will not be added

    // Print the size of the set
    std::cout << "Set size: " << numbers.size() << std::endl;

    // Iterate through the set
    std::cout << "Set elements: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Check if an element exists
    if (numbers.count(20) > 0) {
        std::cout << "20 is in the set" << std::endl;
    }

    // Remove an element
    numbers.erase(20);

    // Check the size after removal
    std::cout << "Set size after removal: " << numbers.size() << std::endl;

    // Clear the set
    numbers.clear();

    // Check if the set is empty
    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

Основные моменты о множествах:

  • Используйте #include <set> для включения библиотеки множеств
  • set<type> создает множество уникальных элементов
  • insert() добавляет элементы (дубликаты игнорируются)
  • count() проверяет наличие элемента
  • erase() удаляет элемент
  • clear() удаляет все элементы
  • empty() проверяет, является ли множество пустым
  • Элементы автоматически сортируются

Сортировка элементов с использованием алгоритма sort из STL

На этом этапе вы узнаете, как использовать алгоритм sort из Стандартной Шаблонной Библиотеки (STL) для упорядочивания элементов в порядке возрастания или убывания. Библиотека <algorithm> предоставляет мощные возможности сортировки для различных контейнеров.

Откройте WebIDE и создайте новый файл с именем sort_demo.cpp в директории ~/project:

touch ~/project/sort_demo.cpp

Добавьте следующий код в файл sort_demo.cpp:

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

int main() {
    // Create a vector of integers
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3};

    // Print original vector
    std::cout << "Original vector: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Sort the vector in ascending order
    std::sort(numbers.begin(), numbers.end());

    // Print sorted vector
    std::cout << "Sorted vector (ascending): ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Sort the vector in descending order
    std::sort(numbers.begin(), numbers.end(), std::greater<int>());

    // Print vector sorted in descending order
    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:

  • Подключайте библиотеку <algorithm> для сортировки
  • std::sort() работает с различными контейнерами
  • По умолчанию сортировка выполняется в порядке возрастания
  • std::greater<type>() выполняет сортировку в порядке убывания
  • Сортировка выполняется на месте, изменяя исходный контейнер
  • Алгоритм эффективно работает с разными типами контейнеров

Поиск элементов с использованием алгоритмов STL

На этом этапе вы узнаете, как использовать алгоритмы STL для поиска элементов в контейнерах. Библиотека <algorithm> предоставляет мощные функции для поиска и нахождения элементов.

Откройте WebIDE и создайте новый файл с именем find_demo.cpp в директории ~/project:

touch ~/project/find_demo.cpp

Добавьте следующий код в файл find_demo.cpp:

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

int main() {
    // Create a vector of integers
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3, 8};

    // Find first occurrence of a specific element
    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;
    }

    // Count occurrences of an element
    int count = std::count(numbers.begin(), numbers.end(), 8);
    std::cout << "Number of 8s in the vector: " << count << std::endl;

    // Find if any element is greater than 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;

    // Find the minimum and maximum elements
    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() находят минимальное и максимальное значения
  • Лямбда - функции можно использовать для настройки условий поиска
  • Возвращаемые итераторы указывают на найденные элементы

Итерация по контейнерам

На этом этапе вы узнаете различные способы итерации по контейнерам STL с использованием различных методов перебора. Мы рассмотрим циклы for на основе диапазона (range-based for loops), итераторы и традиционный индексный способ перебора.

Откройте WebIDE и создайте новый файл с именем iteration_demo.cpp в директории ~/project:

touch ~/project/iteration_demo.cpp

Добавьте следующий код в файл iteration_demo.cpp:

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

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

    // Method 1: Range-based for loop (most modern and readable)
    std::cout << "Vector iteration (range-based for):" << std::endl;
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // Method 2: Iterator-based iteration
    std::cout << "Vector iteration (iterators):" << std::endl;
    for (auto it = numbers.begin(); it!= numbers.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // Method 3: Index-based iteration
    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 iteration
    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 помогает с выводом типа
  • Различные контейнеры поддерживают разные методы итерации

Использование стека (Stack) и очереди (Queue) из STL

На этом этапе вы узнаете о двух важных адаптерах контейнеров STL: стеке (stack) и очереди (queue). Эти контейнеры предоставляют специализированные операции для управления данными по принципу "последним пришел - первым ушел" (LIFO - Last In, First Out) и "первым пришел - первым ушел" (FIFO - First In, First Out).

Откройте WebIDE и создайте новый файл с именем stack_queue_demo.cpp в директории ~/project:

touch ~/project/stack_queue_demo.cpp

Добавьте следующий код в файл stack_queue_demo.cpp:

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

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

    // Push elements onto the stack
    myStack.push(10);
    myStack.push(20);
    myStack.push(30);

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

    // Remove top element
    myStack.pop();
    std::cout << "Top element after pop: " << myStack.top() << std::endl;
    std::cout << "Stack size: " << myStack.size() << std::endl;

    // Queue demonstration
    std::queue<std::string> myQueue;

    // Add elements to the 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;

    // Remove front element
    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, LIFO - Последним пришел, первым ушел)
    • push() добавляет элемент на вершину стека
    • pop() удаляет элемент с вершины стека
    • top() возвращает элемент, находящийся на вершине стека
  • Очередь (Queue, FIFO - Первым пришел, первым ушел)
    • push() добавляет элемент в конец очереди
    • pop() удаляет элемент из начала очереди
    • front() возвращает первый элемент очереди
    • back() возвращает последний элемент очереди
  • У обоих контейнеров есть метод size() для проверки количества элементов
  • Необходимо подключить заголовочные файлы <stack> и <queue>

Обработка безопасности контейнеров в случае исключений

На этом этапе вы узнаете, как обрабатывать исключения и обеспечить безопасную работу с контейнерами STL. Обработка исключений помогает предотвратить аварийное завершение программы и обеспечивает надежное управление ошибками.

Откройте WebIDE и создайте новый файл с именем exception_safety_demo.cpp в директории ~/project:

touch ~/project/exception_safety_demo.cpp

Добавьте следующий код в файл exception_safety_demo.cpp:

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

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

    try {
        // Attempt to access an element from an empty vector
        std::cout << "Attempting to access element from empty vector:" << std::endl;
        numbers.at(0);  // This will throw an out_of_range exception
    }
    catch (const std::out_of_range& e) {
        std::cout << "Out of Range Error: " << e.what() << std::endl;
    }

    // Safe element addition
    try {
        numbers.push_back(10);
        numbers.push_back(20);
        std::cout << "Vector size: " << numbers.size() << std::endl;

        // Safe element access
        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() {
    // Demonstrate vector exception safety
    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 для обработки потенциальных исключений.
  • Исключение std::out_of_range выбрасывается при попытке доступа к несуществующему элементу вектора.
  • Метод at() выполняет проверку границ, в отличие от оператора [].
  • Сначала обрабатывайте конкретные исключения, а затем более общие.
  • Всегда обрабатывайте потенциальные исключения, чтобы предотвратить аварийное завершение программы.
  • Используйте стандартные классы исключений из <stdexcept>.

Итоги

В этом практическом занятии (лабораторной работе) вы узнали о различных компонентах Стандартной Шаблонной Библиотеки C++ (C++ Standard Template Library, STL) и о том, как эффективно их использовать. Вы начали с изучения контейнера vector, который представляет собой динамический массив, размер которого может изменяться. Вы научились добавлять и удалять элементы, обращаться к ним по индексам и проходить по вектору с использованием цикла for на основе диапазона.

Затем вы углубились в изучение контейнера list, который представляет собой реализацию двусвязного списка. Вы узнали, как выполнять общие операции с связным списком, такие как вставка, удаление и обход элементов. Вы также изучили контейнер map, который позволяет хранить пары "ключ - значение", и контейнер set, который хранит уникальные элементы. Кроме того, вы научились использовать алгоритмы STL, такие как sort и find, для манипулирования и поиска элементов в этих контейнерах. Наконец, вы изучили контейнеры stack и queue и обсудили важность безопасности в случае исключений при работе с компонентами STL.