Добавить методический материал по двумерным массивам
Родитель:
253504b
· сравнить с родителем
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 строки матрицы случайно разделяют один список.