Java Notes
Two-dimensional arrays as arrays of arrays
Arrays of arrays
Java builds multi-dimensional arrays from many one-dimensional arrays, the so-called "arrays of arrays" approach.
There are a couple of interesting consequences of this: Rows may be different sizes. Also, each row is an object (an array) that can be used independently.
Multi-dimensional arrays are built from multiple one-dimensional arrays
As with all arrays, the new
keyword must be used
to allocate memory for an array. For example,
int[][] a = new int[2][4];
This two-dimensional array will have two rows and four columns.
This actually allocates 3 objects: a one-dimensional array of 2 elements to hold each of the actual row arrays, and a two one-dimensional arrays of 4 elements to represent the contents of the rows.
+-----+ +-----+-----+-----+-----+ |a[0] | -> | [0] | [1] | [2] | [3] | | | +-----+-----+-----+-----+ +-----+ | | +-----+-----+-----+-----+ |a[1] | -> | [0] | [1] | [2] | [3] | +-----+ +-----+-----+-----+-----+ |
In Java two-dimensional arrays are implemented is a one-dimensional array of one-dimensional arrays -- like this. |
Processing 2-dimensional arrays using .length
Notice in the following example how the rows are handled as separate objects. For example,
int[][] a2 = ...; // Print array even tho we don't know the original size. for (int r=0; r < a2.length; r++) { for (int c=0; c < a2[r].length; c++) { System.out.print(" " + a2[r][c]); } System.out.println(""); }
Trick: Ignoring the zeroth row
Sometimes you want to use natural input values as an index, the real values
that that data has instead of starting with zero.
Let's take the case of data that starts with the value 1, like the
day of the month.
The standard approach is to subtract one from every
day value that's used as an index. This is annoying
and error prone. Another way to do handle this case is
to declare the array with an extra element, eg, 32 if dealing
with the days in the month, then ignoring the zeroth element.
If you're dealing with a two dimensional array, for example
the accidents
array from the previous page,
you can even deallocate the first row so there won't be any
possibility of referencing the zeroth day. For example,
static final int DAYS = 32; static final int HOURS = 24; . . . int[][] accidents = new int[DAYS][HOURS]; accidents[0] = null;
Because two-dimensional arrays are stored by row, you can do this. You can use the trick of allocating more columns to use the natural data, but you can't deallocate a column.
Ragged arrays - Uneven rows
One consequence of arrays of arrays is that each row can be a different size.
For example, we could create a lower triangular array, allocating each row "by hand" as follows.
Note how new
can be used with only the row dimension.
int[][] tri; //... Allocate each part of the two-dimensional array individually. tri = new int[10][]; // Allocate array of rows for (int r=0; r < tri.length; r++) { tri[r] = new int[r+1]; // Allocate a row } //... Print the triangular array (same as above really) for (int r=0; r<tri.length; r++) { for (int c=0; c<tri[r].length; c++) { System.out.print(" " + tri[r][c]); } System.out.println(""); }
Triangular array example - distance table
A good example of a triangular array is one of those tables of the distance between two cities that is often in the front of some road atlas covers. The distance from New York to Chicago is the same as the distance from Chicago to New York - there's not need to have it twice in the same table - at least if you have a need for that remaining space.
Commentary: Two ways to store multi-dimensional arrays
There are two ways to implement 2-dimensional arrays. Many languages reserve a block of memory large enough to hold all elements of the full, rectangular, array (number of rows times number of columns times the element size). Some languages, like Java, build multi-dimensional arrays from many one-dimensional arrays, the so-called "arrays of arrays" approach. C++ supports both styles.