Добавить методический материал по двумерным массивам #2
1 файл изменён
+62
Войди, чтобы оставлять замечания к строкам.
Показать разницуСкрыть разницу
| @@ -0,0 +1,62 @@ | |||
| 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 строки матрицы случайно разделяют один список. | ||