Getting Started
Two-dimensional (2D) arrays are fundamental for organizing data in a grid-like structure, similar to a spreadsheet, a game board, or a pixelated image. To perform meaningful operations on this data—like finding the total score, locating the brightest pixel, or checking for a winning move—we need systematic procedures, or algorithms, to visit and process each element in the grid. This chapter focuses on the core algorithms for traversing and manipulating data within 2D arrays.
What You Should Be Able to Do
Implement nested loops to traverse all elements of a 2D array.
Write code that traverses a 2D array in row-major order.
Write code that traverses a 2D array in column-major order.
Develop an algorithm to compute a result from all elements, such as a sum or average.
Develop an algorithm to find, count, or modify elements that meet specific criteria.
Key Concepts & Java Implementation
The Core Idea
A 2D array is an array of arrays. To access every element, you cannot use a single loop; you need a loop inside another loop. This is called a nested loop. The outer loop typically iterates through the rows, and for each row, the inner loop iterates through all the columns in that row.
The order in which you visit the elements is called the traversal order. The two most common traversal patterns for 2D arrays are:
Row-Major Order: Processing the array one row at a time, from left to right across each column. This is the most common and natural traversal method in Java.
Column-Major Order: Processing the array one column at a time, from top to bottom down each row.
These traversal patterns form the backbone of any algorithm that needs to inspect every element in a 2D array, such as finding the maximum value, counting occurrences of a number, or summing all elements.
Syntax & Implementation
In Java, a 2D array arr has properties that are essential for creating correct loops:
arr.lengthgives the number of rows.arr[i].lengthgives the number of columns in rowi.
Annotated Java Example 1: Row-Major Traversal
This is the standard way to iterate through a 2D array. The outer loop controls the row index, and the inner loop controls the column index.
public class TraversalExamples {
public static void printRowMajor(int[][] grid) {
// The outer loop iterates from the first row (index 0) to the last.
for (int r = 0; r < grid.length; r++) {
// The inner loop iterates from the first column (index 0) to the last in the CURRENT row.
for (int c = 0; c < grid[r].length; c++) {
// Access the element at the current row 'r' and column 'c'.
System.out.print(grid[r][c] + " ");
}
// Move to the next line after printing all elements in a row.
System.out.println();
}
}
}
Annotated Java Example 2: Column-Major Traversal
To traverse in column-major order, the loops are swapped. The outer loop iterates through all possible column indices, and the inner loop iterates through the rows.
public class TraversalExamples {
public static void printColumnMajor(int[][] grid) {
// Assume the grid is rectangular for this simple example.
// The outer loop iterates from the first column (index 0) to the last.
for (int c = 0; c < grid[0].length; c++) {
// The inner loop iterates from the first row (index 0) to the last.
for (int r = 0; r < grid.length; r++) {
// Access the element at row 'r' and column 'c'.
System.out.print(grid[r][c] + " ");
}
// Optional: Move to the next line after printing all elements in a column.
System.out.println();
}
}
}
Annotated Java Example 3: Algorithm to Sum All Elements
This example builds on row-major traversal to perform a calculation. An "accumulator" variable sum is used to keep a running total.
public class ArrayAlgorithms {
public static int sumAllElements(int[][] data) {
// 1. Initialize an accumulator variable to store the sum.
int sum = 0;
// 2. Use a standard row-major traversal to visit every element.
for (int r = 0; r < data.length; r++) {
for (int c = 0; c < data[r].length; c++) {
// 3. Add the value of the current element to the sum.
sum += data[r][c];
}
}
// 4. Return the final sum after the loops complete.
return sum;
}
}
Tracing & Analysis
Execution Trace
Let's trace the sumAllElements algorithm with a simple 2x3 array: int[][] data = {{10, 20, 30}, {40, 50, 60}};
r | c | data[r][c] | sum (at end of inner loop iteration) |
|---|---|---|---|
| 0 | 0 | 10 | 10 |
| 0 | 1 | 20 | 30 |
| 0 | 2 | 30 | 60 |
| 1 | 0 | 40 | 100 |
| 1 | 1 | 50 | 150 |
| 1 | 2 | 60 | 210 |
After the loops finish, the method returns the final value of sum, which is 210.
Analysis
For algorithms like summing all elements or finding the single maximum value, the traversal order (row-major vs. column-major) does not change the final result. However, the order of access is different. Row-major is generally preferred as it is more conventional in Java and can be more efficient in terms of how computer memory is accessed, though this is not a tested concept. The key is to choose a traversal pattern and apply it consistently.
Java Syntax Quick-Reference
A compact reference for syntax used when working with 2D array algorithms.
| Syntax | Purpose |
|---|---|
int[][] arr; | Declares a 2D array variable that can hold integer values. |
arr.length | Returns the number of rows in the 2D array arr. |
arr[r].length | Returns the number of columns in the row at index r. |
arr[r][c] | Accesses (gets or sets) the element at row r and column c. |
for (int r=0; ...) | The standard for loop structure used for iterating with an index. |
Core Code Examples & Terminology
Traversal: The process of systematically visiting, or accessing, each element in a data structure exactly once. For 2D arrays, this is typically done with nested loops.
Row-Major Order: A traversal pattern that processes all elements in the first row, then all elements in the second row, and so on, until all rows have been visited.
Column-Major Order: A traversal pattern that processes all elements in the first column, then all elements in the second column, and so on, until all columns have been visited.
Nested Loop: A loop placed inside the body of another loop. Nested loops are the standard structure for processing every element of a 2D array.
Core Snippet 1: Standard Row-Major Traversal
for (int r = 0; r < grid.length; r++) { for (int c = 0; c < grid[r].length; c++) { // Process grid[r][c] here } }This code structure visits every element in a 2D array, one row at a time.
Core Snippet 2: Finding the Maximum Value
int maxVal = grid[0][0]; // Assume the first element is the largest for (int r = 0; r < grid.length; r++) { for (int c = 0; c < grid[r].length; c++) { if (grid[r][c] > maxVal) { maxVal = grid[r][c]; } } }This algorithm traverses the grid, updating a variable
maxValwhenever a larger element is found.Core Snippet 3: Counting Elements Matching a Condition
int count = 0; for (int r = 0; r < grid.length; r++) { for (int c = 0; c < grid[r].length; c++) { if (grid[r][c] > 10) { // Condition: element is greater than 10 count++; } } }This algorithm traverses the grid and increments a counter for each element that satisfies a specific condition.
Core Skill Check
Code Tracing: What is the final value of
totalafter this Java code runs?int[][] nums = {{1, 2}, {3, 4}, {5, 6}}; int total = 0; for (int c = 0; c < 2; c++) { for (int r = 0; r < 3; r++) { total += nums[r][c]; } }Debugging: Identify the runtime error in this Java code, assuming
matrixis a 3x4 (3 rows, 4 cols) array.for (int r = 0; r < matrix.length; r++) { for (int c = 0; c < matrix.length; c++) { System.out.print(matrix[r][c]); } }Application: Write a single line of Java code that gets the value from the first row and last column of a 2D array named
board.
Common Misconceptions & Errors
Incorrect Inner Loop Bound: Using
arr.length(the number of rows) as the condition for the inner (column) loop. The inner loop must usearr[r].length(the length of the current row), especially if the array is not rectangular.Index Transposition: Accidentally swapping the row and column indices, such as writing
arr[c][r]when you intendedarr[r][c]. This can lead to incorrect logic or anArrayIndexOutOfBoundsException.Off-by-One Errors: Using
<=in a loop's condition (e.g.,r <= arr.length) will cause the loop to try to access an index that is out of bounds, resulting in anArrayIndexOutOfBoundsException. Array indices go from0tolength - 1.Initializing Min/Max Incorrectly: When finding a minimum or maximum value, initializing your tracking variable to
0can be incorrect if all numbers in the array are negative (for max) or all are large positive numbers (for min). A safer approach is to initialize it to the first element of the array,arr[0][0].
Summary
Implementing algorithms for 2D arrays is a crucial skill for processing grid-based data. The fundamental technique is the nested loop, which allows for a complete traversal of all elements. The most common pattern, row-major order, iterates through each row and then each column within that row. By embedding logic inside these nested loops, we can perform powerful calculations like summing elements, finding the largest or smallest value, or counting elements that meet certain criteria. Mastering these traversal patterns is the key to solving a wide range of problems involving 2D arrays.