JustCaptain kod-buduschego

Добавить методический материал по двумерным массивам

JustCaptain · 2 недели назад fe9c6c08be73ce67e8771ed2945bb1d512df3ae4
1 файл
  • Показать разницуСкрыть разницу
    1 +# Двумерные массивы в C++
    2 +
    3 +Матрица — таблица значений с индексами строки и столбца. Примеры из жизни: расписание уроков, игровое поле, карта высот и пиксели изображения. В задаче матрица размера `rows × cols` содержит `rows` строк и `cols` столбцов; индексы начинаются с нуля.
    4 +
    5 +## Простое представление: вектор векторов
    6 +
    7 +```cpp
    8 +int rows, cols;
    9 +std::cin >> rows >> cols;
    10 +std::vector<std::vector<int>> a(rows, std::vector<int>(cols));
    11 +for (int r = 0; r < rows; ++r)
    12 + for (int c = 0; c < cols; ++c)
    13 + std::cin >> a[r][c];
    14 +```
    15 +
    16 +Обращение `a[r][c]` читается как «строка r, столбец c». Для квадратной матрицы `rows == cols`, для прямоугольной — размеры могут отличаться. Нельзя предполагать квадратность, если это не сказано в условии. Вложенный вектор позволяет строкам иметь разную длину, но каждая внутренняя строка — отдельный `vector`, поэтому вся матрица не обязательно лежит в одном непрерывном блоке памяти.
    17 +
    18 +## Плоское хранение
    19 +
    20 +Для прямоугольной матрицы можно хранить значения в одном векторе длины `rows * cols`. Элемент `(r,c)` лежит по индексу `r * cols + c`:
    21 +
    22 +```cpp
    23 +std::vector<int> a(static_cast<std::size_t>(rows) * cols);
    24 +a[static_cast<std::size_t>(r) * cols + c] = value;
    25 +```
    26 +
    27 +Это хранение единым буфером: удобно для больших матриц и алгоритмов, которым важна непрерывность памяти. Формула использует число столбцов, не строк. Прежде чем выделять память, проверьте допустимость размеров и риск переполнения при их перемножении.
    28 +
    29 +## Обходы
    30 +
    31 +Обычный обход по строкам:
    32 +
    33 +```cpp
    34 +for (int r = 0; r < rows; ++r) {
    35 + for (int c = 0; c < cols; ++c) {
    36 + // обработать a[r][c]
    37 + }
    38 +}
    39 +```
    40 +
    41 +Так элементы читаются в естественном для C++ порядке хранения. Сумма всех элементов стоит `O(rows * cols)`. Обход соседей клетки используйте только после проверки границ: `0 <= nr < rows` и `0 <= nc < cols`. Для направлений часто заводят массивы `dr = {-1, 1, 0, 0}` и `dc = {0, 0, -1, 1}`.
    42 +
    43 +## Память и алгоритмическая сложность
    44 +
    45 +Матрица из `R*C` значений занимает `O(R*C)` памяти. Если задачу можно решить построчно, храните только необходимые строки — иногда дополнительную память удаётся уменьшить с `O(R*C)` до `O(C)`. Например, при вычислении каждой строки динамического программирования могут быть нужны только предыдущая и текущая строки. Различайте память самой входной матрицы и дополнительную память алгоритма.
    46 +
    47 +Поворот или транспонирование матрицы обычно требуют либо нового буфера `O(R*C)`, либо аккуратных операций на месте. Квадратную матрицу можно транспонировать на месте, меняя местами `a[r][c]` и `a[c][r]` только для `c > r`. Для прямоугольной матрицы размеры меняются местами, поэтому простое такое правило не подходит.
    48 +
    49 +## Сравнение языков
    50 +
    51 +Python часто представляет таблицу как список списков: `grid[r][c]`. Создавая матрицу, не используйте `[[0] * cols] * rows`: все строки окажутся ссылками на один и тот же список. Используйте `[[0 for _ in range(cols)] for _ in range(rows)]`.
    52 +
    53 +Rust обычно использует `Vec<Vec<T>>` или плоский `Vec<T>` с индексом `r * cols + c`. Как и в C++, вложенные векторы удобны для строк, а плоский буфер — для одного непрерывного блока. Rust дополнительно проверяет владение и заимствования; C++ программист сам отвечает за границы и время жизни ссылок. У `vector<vector<T>>` внешний `vector` владеет строками, у плоского `vector` — единым хранилищем.
    54 +
    55 +## Частые ошибки
    56 +
    57 +- Перепутаны `rows` и `cols`, особенно при транспонировании.
    58 +- Цикл идёт до `<= rows` вместо `< rows`.
    59 +- Индекс вычислен как `c * rows + r`, хотя правильная формула для построчного хранения — `r * cols + c`.
    60 +- Доступ к соседу происходит до проверки его координат.
    61 +- Создана матрица с `rows * cols`, но произведение переполнилось или объём слишком велик.
    62 +- В Python строки матрицы случайно разделяют один список.