Обход массивов 2D
| English | Русский |
|---|---|
| nested loops/ˈnestɪd luːps/ | вложенных циклов |
| row-major order/rəʊ ˈmeɪdʒə ˈɔːdə/ | порядок по строкам |
| enhanced for/enˈhænst fɔː/ | расширенный for |
Прямоугольная сетка обнажает неверную границу цикла
- Сетка имеет два ряда и три столбца. Цикл, ограниченный g.length для обоих индексов, посещает только первые два столбца.
- Используйте r < g.length и, для каждого ряда, c < g[r].length. Это также обрабатывает строки разной длины, тогда как g[0].length предполагает непустую прямоугольную сетку.
Вложенные циклы для таблицы
- Чтобы посетить каждую ячейку массива размерности 2, используйте вложенные циклы (из раздела 2). Внешний цикл по строкам, внутренний по столбцам:
for (int r = 0; r < g.length; r++) { for (int c = 0; c < g[r].length; c++) { ... g[r][c] ... } }Внутренний цикл проходит полную строку до того, как внешний перейдет к следующей.
Порядок по строкам (row-major)
- Этот вложенный цикл посещает ячейки в порядке построчного обхода: все строки 0, затем строки 1, …
g[0][0], g[0][1], …, g[1][0], g[1][1], … - Это естественный порядок чтения — слева направо, сверху вниз. Для непустого прямоугольного массива столбцы можно использовать как внешний цикл для посещения ячеек по столбцам. Неровный массив требует явного правила обработки столбцов, которых некоторые строки не содержат.
Версия for-each
- Цикл enhanced for по одномерному 2-мерному массиву выдает по одной строке (одномерному 1-мерному массиву) за раз.
for (int[] row : g) { for (int x : row) { ... x ... } } - Внешняя переменная представляет собой целую строку; внутренняя перебирает значения этой строки. Переменная примитивного типа не обновляет сохраненные ячейки при переназначении. Переменная строки остается ссылкой, поэтому индексированный внутренний цикл может изменять
row[c].
Обход по строкам (row-major)
Внешний цикл по строкам, внутренний по столбцам: 1,2,3,4,5,6.
Какая из показанных ниже паттернов обходит каждую ячейку непустого массива int размерности 2-D, у которого все ссылки на строки непусты?
Внешний по строкам, внутренний по столбцам.
Внешний цикл обхода массива в порядке строк 2-мерного измерения должен ограничиваться...
Внешний цикл по строкам использует g.length; внутренний цикл по ячейкам использует g[r].length, что позволяет обрабатывать строки unequal длины.
Для сетки размером 2 строки на 3 столбца, сколько ячеек посетит вложенный цикл?
строки × столбцы = 2 × 3 = 6.
Обход по строкам посещает ячейки в порядке...
Обход по строкам = слева направо, сверху вниз.
В конструкции for (int[] row : g) переменная row представляет собой...
Переменная внешнего цикла for-eх является массивом строки.
Использование g.length для обоих границ цикла всегда вызывает исключение на любой неквадратной прямоугольной сетке.
Неверно: в сетке с 2 строками и 3 столбцами он посещает лишь два столбца и молчаливо пропускает ячейки. В сетке, где высота превышает ширину, он может выйти за границу строк.
Правильные границы
- Верхняя граница внешнего цикла:
r < g.length(строки). Верхняя граница внутреннего цикла:c < g[r].length(длина текущей строки). Использование неверной длины для цикла — это тонкая ошибка в неквадратных массивах. - Для непустого прямоугольного массива
g[0].lengthтакже дает общее количество столбцов, а тело внутреннего цикла выполняетсяrows × columnsраз. Для неровных строк суммируйте длины строк; все ссылки на строки должны быть отличными от null.
Используйте g.length для строк и g[r].length для ячеек текущей строки. Использование количества строк в качестве обеих границ может пропустить столбцы в широком массиве или выйти за допустимые пределы в высоком массиве. Пустой внешний массив не требует обращения к g[0]; пустая строка требует явного правила обработки перед чтением ее длины.
Order the cells visited in row-major traversal of a 2×2 grid.
The inner loop finishes one row before the outer loop advances.
Для int[][] g = {{1, 2, 3}, {}, {4}};, сколько ячеек обходит обход по строкам?
Сложите длины строк: 3 + 0 + 1 = 4. Пустая строка не вносит вклад в количество ячеек.
Суммирование одномерного (2-D) массива:
for (int r = 0; r < g.length; r++)for (int c = 0; c < g[r].length; c++)sum += g[r][c];— посещает все ячейки построчно, предполагая, что ни одна строка не является null.
Перенесите рассуждения на новый случай
- Для
int[][] g = {{1, 2, 3}, {}, {4}};длины строк равны 3, 0 и 1. Границы по строкам охватывают четыре ячейки и в сумме дают 10;g[0].lengthне является допустимой границей для каждой строки. - Вы можете изменить row[c] с помощью индексированного внутреннего цикла; переназначение примитивной переменной x во внутреннем цикле enhanced for не изменяет сохраненную ячейку.
Обходите 2-мерный массив с помощью вложенных циклов: внешний по строкам (r < g.length), внутренний по столбцам (c < g[r].length), обращаясь к ⟨g[r][c]⟩. Это посещает ячейки в порядке построчного хранения (сумма длин строк; ⟨rows × columns⟩ для прямоугольной сетки). Расширенный for (for (int[] row : g)) передает ссылку на одну строку за раз; присваивание примитивной переменной внутреннего цикла не изменяет сохраненную ячейку.