There are a few algorithms and idioms that are specific to 2D arrays. And then there are ways we can apply the patterns and algorithms we already know how to use with one-dimensional arrays to 2D arrays. In this section we will quickly run through some of those.
Just like for loops and 1D arrays are made for each other, nested for loops and 2D arrays are similarly well-suited. Using a regular for loop to access the elements of a 2D array looks like this:
That loop traverses the array in whatβs called row-major order which just means that we visit every element of each row before moving to the next row. Itβs also possible to visit the elements in column-major order which means going down each column before moving to the next one. To implement a column-major traversal we simply need to swap the order of the two loop headers so the column loop is now the outer loop:
What does the following code do? Add another row of numbers to the matrix. Will the loops traverse this row too? And what does the expression a.length * a[0].length represent?
Since 2D arrays are just regular arrays we can also use nested enhanced for loops to loop through all elements in an array. When we use enhanced for loops with a 2D array, the fact that we can only loop forward through the array means that we can only easily loop through a 2D array in row-major order. But when thatβs what we want, and we donβt need access to the indices themselves or to modify the array elements, an enhanced for loop can be nicely concise.
Subsection6.5.3Applying 1D algorithms to 2D arrays
All of the array algorithms we discussed in SectionΒ 6.3Β Array algorithms can also be applied to 2D arrays. The only wrinkle is now we have two dimensions to play with. So we could, for instance, write an algorithm to find the row in a 2D array whose values add up to the largest total by applying the maximizing pattern to the outer array and the summing pattern to each inner array.
int biggestRowIndex = 0;
int biggestSum = Integer.MIN_VALUE;
// This loop is finding the index of the row with the biggest total
for (int r = 0; r < array.length; r++) {
int sum = 0;
// This loop is summing the current row
for (int c = 0; c < array[r].length; c++) {
sum += array[r][c];
}
if (sum > biggestSum) {
biggestSum = sum;
biggestRowIndex = r;
}
}
We could use the same basic algorithm but with a column-major traversal to find the number of the column with the largest sum. And we can endlessly mix and match, write an outer summing loop that totals up the smallest value in each row. Or write an outer any loop around an inner all loop to check whether any row consists of all even numbers. Or write an outer loop that reverses the order of rows of an array while the inner loop reverses the values within each row. The combinations are endless.
Relatedly we can also apply the idea of any of the 1D algorithms that accumulate a value to 2D arrays by accumulating across all the values in the 2D array. In that case we just use nested loops and do the accumulation in the body of the inner loop. Compare these two bits of code. On the left, accumulating the total in a 1D array and on the right, the same algorithm with a 2D array.
What will the following code print out? Can you complete the method called getTotalForCol that gets the total for a column? To do this, you must loop through the rows. The arrayβs length will tell you how many rows you have since it is an array of arrays, while the length of the arrayβs first element will tell you how many columns.
The following has the correct code to find the largest value in a 2D array. Drag the blocks from the left into the correct order on the right. Check your solution by clicking on the Check button. You will be told if any of the blocks are in the wrong order.
public int getLargest(int[][] arr)
{
---
int largest = arr[0][0];
int current = 0;
for(int r=0;r < arr.length;r++)
{
---
for(int c=0;c < arr[0].length;c++)
{
---
current = arr[r][c];
if (current > largest)
{
---
largest = current;
---
} // end if
---
} // end column loop
---
} // end row loop
return largest;
---
} // end method
Hint.
You can step through this code using the Java Visualizer by clicking on the following Java Visualizer.
Finally, we can write algorithms that operate on arbitrary slices of a 2D array such as a single row, a single column, or some rectangular subset of the array. We will need to use regular for loops because we need control over exactly what indices we use, but beyond that itβs just a matter of determining what the 2D indices are of the elements in the slice we want.
Slicing a single row or a single column turns into a 1D problem where we just have to pick out the elements we want by fixing either the row or column index we use. For instance:
// c never changes so we loop down the column
for (int r = 0; r < array.length; r++) {
System.out.println(array[r][c]);
}
Rectangular slices are still 2D so we still need nested loops. We control the slice by where we start and end the row and column loops. Here are some examples:
(AP 4.12.A.1) Nested iteration statements (loops) are used to traverse and access all or an ordered sequence of elements in a 2D array. Since 2D arrays are stored as arrays of arrays, the way 2D arrays are traversed using for loops and enhanced for loops is similar to 1D array objects.
(AP 4.12.A.1) Nested iteration statements can be written to traverse the 2D array in row-major order, column-major order, or a uniquely defined order. Row-major order refers to an ordering of 2D array elements where traversal occurs across each row, whereas column-major order traversal occurs down each column.
(AP 4.12.A.2) The outer loop of a nested enhanced for loop used to traverse a 2D array traverses the rows. Therefore, the enhanced for loop variable must be the type of each row, which is a 1D array. The inner loop traverses a single row. Therefore, the inner enhanced for loop variable must be the same type as the elements stored in the 1D array. Assigning a new value to the enhanced for loop variable does not change the value stored in the array.