Добавить раздел «Массивы»
Родитель:
253504b
· сравнить с родителем
1 файл
-
Показать разницуСкрыть разницу
1 +# Массивы в C++ 2 + 3 +Материал о последовательностях, динамической памяти и алгоритмах. Затем решите 12 авторских задач: [Intern](Intern.md), [Middle](Middle.md), [Senior](Senior.md) — по четыре задачи на уровень. 4 + 5 +## Последовательность и выбор контейнера 6 + 7 +Массив — упорядоченный ряд значений одного типа. Индексация начинается с нуля: при `n` элементах индексы от `0` до `n-1`. Для значений фиксированного размера есть `std::array<T, N>` (`<array>`); для размера, известного во время работы, обычно используют `std::vector<T>` (`<vector>`). Встроенный `T a[N]` тоже фиксированного размера. Стандартный C++ не поддерживает массивы переменной длины. 8 + 9 +```cpp 10 +std::vector<int> temperatures{18, 20, 17}; 11 +std::cout << temperatures[1]; // 20 12 +``` 13 + 14 +Вектор хранит элементы непрерывно и знает число элементов. `size()` — число созданных элементов, `capacity()` — вместимость уже выделенной памяти. Не обращайтесь к элементу по индексу `size()` или выше. `operator[]` не проверяет границу; `at(i)` проверяет и бросает исключение. Пустой вектор нельзя индексировать. 15 + 16 +## Жизненный цикл памяти 17 + 18 +```cpp 19 +std::vector<int> a; 20 +a.reserve(1000); // место зарезервировано, size() всё ещё 0 21 +for (int i = 0; i < 1000; ++i) a.push_back(i); 22 +``` 23 + 24 +`reserve` резервирует capacity, но не создаёт элементов. Для изменения количества элементов предназначен `resize`. Если размер заранее известен, создайте `std::vector<int> a(n)`. При исчерпании capacity `push_back` может выделить новый участок памяти и переместить элементы. Добавление в конец амортизированно `O(1)`, но конкретное перераспределение стоит `O(n)`. После него ссылки, указатели и итераторы на элементы могут стать недействительными. `insert` и `erase` в середине обычно `O(n)`, так как хвост сдвигается. 25 + 26 +`clear()` удаляет элементы, но не гарантирует освобождения буфера. `shrink_to_fit()` — необязательный запрос реализации. Обычно не нужны ручные `new[]` и `delete[]`: `std::vector` автоматически освобождает память по RAII и помогает избежать утечек и двойного освобождения. 27 + 28 +## Python и Rust 29 + 30 +Python `list` растёт при `append`, индексируется с нуля, но хранит ссылки на объекты; это не то же расположение данных, что компактный `std::vector<int>`. Для крупных числовых данных применяют, например, NumPy. Rust `Vec<T>` похож на вектор C++ по идее владеющего расширяемого буфера и автоматически освобождает память. Rust проверяет правила владения/заимствования; `v.get(i)` возвращает безопасный результат `Option`, а неверный `v[i]` паникует. В C++ выход `a[i]` за границы — неопределённое поведение, а время жизни ссылок контролирует программист. 31 + 32 +## Сложность, память и ошибки 33 + 34 +Доступ по индексу — `O(1)`, проход/поиск — `O(n)`, добавление в конец — амортизированно `O(1)`, вставка в начало — `O(n)`. Копирование вектора из `n` элементов требует `O(n)` времени и памяти; большой массив, который функция только читает, обычно передают как `const std::vector<T>&`. Отличайте память входа от дополнительной памяти алгоритма: `O(1)` дополнительной памяти означает фиксированное число временных переменных, а не отсутствие самого входного массива. 35 + 36 +Частые ошибки: индексация за границей; путаница `reserve` и `resize`; использование ссылки после перераспределения; копирование массива без необходимости; `O(n²)` из-за многократного удаления первого элемента; переполнение суммы (при необходимости используйте `long long`). `size_t` беззнаковый, поэтому осторожно смешивайте его с отрицательными индексами типа `int`.