Suppose that you had a list of numbers and wanted to find the sum. Assuming that each number was relatively small in magnitude and the list was relatively short (so that even the sum would be relatively small in magnitude), one reasonable approach would be to keep in mind a "sum-so-far", initially zero, and then examine the numbers in the list one by one, each time adding the "current" number to the sum-so-far.

current number | sum-so-far |
---|---|

- | 0 |

4 | 4 |

12 | 16 (i.e., 4+12) |

-6 | 10 (i.e., 4+12+-6) |

2 | 12 (i.e., 4+12+-6+2) |

5 | 17 (i.e., 4+12+-6+2+5) |

-3 | 14 (i.e., 4+12+-6+2+5+-3) |

For example, suppose that the list were ⟨ 4 12 -6 2 5 -3 ⟩. Then you would go through a mental process as described by the table to the right:

The first row shows the initial situation, before examining any of the numbers in the list. Each subsequent row shows the number currently being examined and the result of adding it to the "sum-so-far". Obviously, by the time we have examined the last number and added it to the sum-so-far, the sum-so-far is equal to the sum of all the numbers in the list. (In fact, more generally you can say that, at any given moment, the sum-so-far value is equal to the sum of the numbers that have been examined up to that moment.)

We can mimic this process using Java in a straightforward way, as
expressed in the following method. The role of the "list of numbers"
is played by the parameter `a[]`, which is an array of values
of type `int`. (Of course, the same logic would work just as
well with an array of type `double[]`.)

/* Returns the sum of the elements in the specified array (a[]). */ public static int sumOf(int[] a) { int sumSoFar = 0; // loop invariant: sumSoFar = sum of elements in a[0..i-1] for (int i=0; i != a.length; i = i+1) { sumSoFar = sumSoFar + a[i]; } return sumSoFar; } |

A more versatile version of the `sumof()` method would allow
a caller to identify a segment of the array to be summed.
(An **array segment** is simply a contiguous portion of an array.)
In analogy to the `substring()` method of the class
`String`, we identify an array segment by referring
to the location at which it begins and the location immediately
after where it ends.

/* Returns the sum of the elements in the specified array segment, ** namely a[low..high). ** Precondition: 0<=low<=high<=a.length */ public static int sumOf(int[] a, int low, int high) { int sumSoFar = 0; // loop invariant: sumSoFar = sum of elements in a[low..i) for (int i=low; i != high; i = i+1) { sumSoFar = sumSoFar + a[i]; } return sumSoFar; } |

Having developed this more versatile version of `sumOf()`,
we should replace the original one by the following:

/* Returns the sum of the elements in the specified array (a[]). */ public static int sumOf(int[] a) { return sumOf(a, 0, a.length); } |

Now we turn to a similar problem, that of finding the maximum value in an array. Again consider how you might do this "manually" if given a list of numbers. As with finding the sum, here you would examine each number in the list, one by one. But this time, rather than adding the current number to the sum-so-far, you would compare it to a max-so-far value that you were keeping in mind. If the current value exceeded that of the max-so-far value, you would replace the latter with the current number, as now it qualifies as the maximum of the numbers seen so far.

For example, suppose that the list were ⟨ 4 7 0 2 9 -3 ⟩. Then you would go through a mental process as described by this table:

current number | max-so-far |
---|---|

4 | 4 (i.e., maximum of {4}) |

7 | 7 (i.e., maximum of {4,7}) |

0 | 7 (i.e., maximum of {4,7,0}) |

2 | 7 (i.e., maximum of {4,7,0,2}) |

9 | 9 (i.e., maximum of {4,7,0,2,9}) |

-3 | 9 (i.e., maximum of {4,7,0,2,9,-3}) |

Using the `sumOf()` method as a template, we modify it in
the rather obvious way to obtain this:

/* Returns the maximum of the elements in the specified array (a[]). ** pre: a.length != 0 */ public static int maxOf(int[] a) { int maxSoFar = a[0]; // loop invariant: maxSoFar = maximum of the elements in a[0..i) for (int i=1; i != a.length; i = i+1) { if (a[i] > maxSoFar) { maxSoFar = a[i]; } } return maxSoFar; } |

One difference between the `sumOf()` and `maxOf()`
methods is that, because there is no value that stands in the same
relation to the **max** operator as zero does to the addition
operator (namely, zero is the **identity** of addition, but max
has no identity element), it is necessary to initialize the
"max-so-far" variable to one of the array elements.

To generalize `maxOf()` to return the maximum element in an
array segment, we would follow exactly the same steps as
we did in generalizing `sumOf()` above. Specifically,
we would replace `0`, `1`, and `a.length`
by `low`, `low+1`, and `high`, respectively.

From a client's point of view, having a method that identifies the
maximum value in an array could be useful.
More useful, however, would be to have a method that identifies a
**location** at which an array's maximum value occurs.
After all, if you know where the maximum is located, you can easily
determine its value simply by referring to the array and using the
location of the maximum as the subscript! That is, if `r`
is a location of array `b` at which `b`'s maximum
occurs, the expression `b[r]` is that maximum value.

So let's develop a new method, `locOfMax()`, that identifies
the lowest-numbered location of an array where the array's maximum value
occurs. Given that we already have the `maxOf()` method,
perhaps the most obvious solution is this:

/* Returns the lowest-numbered location at which occurs the maximum ** value of the specified array (a[]). */ public static int locOfMax(int[] a) { int maxVal = maxOf(a); // determine the maximum value in a[] // Now search a[] until we find that maximum value int i=0; // loop invariant: maxVal does not occur in a[0..i) while (a[i] != maxVal) { i = i+1; } return i; } |

This works, but notice that determining the maximum requires a complete "pass" over the array and then finding its first occurrence requires at least a partial pass and up to a full pass. If, during the first pass, we remember not only the max-so-far value but also its location, no second pass would be necessary. Following this idea, and also assuming that the array's length is non-zero, we get:

/* Returns the lowest-numbered location containing a maximum of ** the elements in the specified array (a[]). */ public static int locOfMax(int[] a) { int maxSoFar = a[0]; int locOfMaxSoFar = 0; // loop invariant: maxSoFar = maximum of the elements in a[0..i) && // maxSoFar = a[locOfMaxSoFar] for (int i=1; i != a.length; i = i+1) { if (a[i] > maxSoFar) { maxSoFar = a[i]; locOfMaxSoFar = i; } } return locOfMaxSoFar; } |

But notice that `maxSoFar = a[locOfMaxSoFar]` is an invariant
of the loop. Which means that wherever the value of `maxSoFar`
is used, we could just as well use `a[locOfMaxSoFar]`.
Which is to say that we can write the method without the
`maxSoFar` variable, like this:

/* Returns the lowest-numbered location containing a maximum of ** the elements in the specified array (a[]). */ public static int locOfMax(int[] a) { int locOfMaxSoFar = 0; // loop invariant: a[locOfMaxSoFar] = maximum of the elements in a[0..i) for (int i=1; i != a.length; i = i+1) { if (a[i] > a[locOfMaxSoFar]) { locOfMaxSoFar = i; } } return locOfMaxSoFar; } |

Generalizing this (as we did for sumOf()) to allow a caller to ask for the location of a maximum within an array segment, we get this:

/* Returns the lowest-numbered location within a[low..high) ** occupied by a maximum of that segment. */ public static int locOfMax(int[] a, int low, int high) { int locOfMaxSoFar = low; // loop invariant: a[locOfMaxSoFar] = maximum of the elements in a[low..i) for (int i=low+1; i != high; i = i+1) { if (a[i] > a[locOfMaxSoFar]) { locOfMaxSoFar = i; } } return locOfMaxSoFar; } |

So now we can write the non-generalized version so that it makes use of the generalized version:

/* Returns the lowest-numbered location containing a maximum of ** the elements in the specified array (a[]). */ public static int locOfMax(int[] a) { return locOfMax(a, 0, a.length); } |

Having written the generalized and non-generalized versions of
`locOfMax()` in this way, now we can write proper versions
of `maxOf()`:

/* Returns the maximum of the elements in the specified array ** segment (a[low..high-1]). */ public static int maxOf(int[] a, int low, int high) { return a[locOfmax(a, low, high)]; } |

/* Returns the maximum of the elements in the specified array (a[]). */ public static int maxOf(int[] a) { return maxOf(a,0,a.length); } |

Now we consider the problem of reversing the elements in an array. That is, we want to modify the contents of an array so that, in the end, the values are in reverse order relative to their original order.

For example, if initially the array were

0 1 2 3 4 5 6 7 +----+----+----+----+----+----+----+----+ | 5 | 12 | -7 | 2 | 0 | 14 | -1 | 3 | +----+----+----+----+----+----+----+----+ |

0 1 2 3 4 5 6 7 +----+----+----+----+----+----+----+----+ | 3 | -1 | 14 | 0 | 2 | -7 | 12 | 5 | +----+----+----+----+----+----+----+----+ |

One way to achieve this result is to carry out a bunch of
**swap** operations. This term is commonly used to refer to
the act of interchanging the values of two variables.
In particular, we would swap the values at these pairs of locations:
(0,7), (1,6), (2,5), and (3,4).

Do you detect a pattern here? Each pair of locations has the same sum, 7, which, not coincidentally, is one less than the array's length. Try it with an array of any length and you will see that the same pattern holds. Indeed, if the array's length is N (and thus its index range is 0..N−1), the pairs of locations whose values should be swapped is (0,N−1), (1,N−2), (2,N−3), ...., each of which adds up to N−1. Thus, letting i be the first (and smaller) component of any such pair of locations, the second component j must satisfy both i+j = N−1 and i < j. Solving the former for j, we get j = N−1−i. Thus, each pair of locations whose values should be swapped is of the form (i, N−1−i).

Given that j = N−1−i, the inequality i < j translates to
i < N−1−i, which is equivalent to 2i < N−1.
All this analysis leads to the following Java method, which employs
the yet-to-be-written `swap()` method:

/* Reverses the elements in the specified array (a[]). */ public static int reverse(int[] a) { final int N = a.length; for (int i=0; 2*i < N-1; i = i+1) { swap(a, i, N-1-i); } } |

As the reader should have surmised, the method call `swap(b,k,m)`
is intended to have as its effect to swap the elements at locations
k and m of array b[].

Before we deal with the design of the `swap()` method, let's develop
an alternative version of `reverse()`. Above we reasoned that every
"swap location pair" (i,j) must satisfy i < j and j = N−1−i.
We used these to determine the loop guard and the second argument to be
passed to the `swap()` method.

But we could just as well use j as a program variable and maintain its
value so that j = N−1−i is an invariant.
Here is the new version of `reverse()`, which uses a for-loop
having two loop-control variables:

/* Reverses the elements in the specified array (a[]). */ public static int reverse(int[] a) { final int N = a.length; for (int i=0, j=N-1; i < j; i = i+1, j = j-1) { swap(a, i, j); } } |

Notice that, within the for-loop heading, the first and third components can be a sequence of statements separated by commas.

An equivalent method that uses a while-loop is as follows:

/* Reverses the elements in the specified array (a[]). */ public static int reverse(int[] a) { int i=0, j = a.length - 1; while (i < j) { swap(a, i, j); i = i+1; j = j-1; } } |

As for swapping the values of two variables, suppose that you have
variables `x` and `y` and you want to swap their values.
Your first inclination might be to use the following pair of assignments:

But that won't work, because not only will `x` end up with
`y`'s original value, but so will `y`! Why? Because
the first assignment obliterates `x`'s original value, replacing
it with `y`'s. Thus, the second assignment copies `x`'s
new value (which was `y`'s original value) back into `y`!

To do it correctly, we need to employ an auxiliary variable to
"remember" `x`'s original value and then, after copying
`y`'s value into `x`, to assign the remembered value
to `y`:

Using the same idea but where the variables being swapped are array elements, we get the following method:

/* Swaps the elements in the specified locations (k and m) of ** the specified array (b[]). */ public static void swap(int[] b, int k, int m) { int temp = a[k]; a[k] = a[m]; a[m] = temp; } |

In analogy with the `sumOf()` and `maxOf()` examples,
we can make the `reverse()` method more versatile by allowing
a caller to specify an array segment that is to be reversed.
Here it is:

/* Reverses the elements in the specified array segment (a[low..high)). */ public static int reverse(int[] a, int low, int high) { int i = low, j = high - 1; while (i < j) { swap(a, i, j); i = i+1; j = j-1; } } |

For another variation, consider that the caller may not want to modify an existing array but rather to create a new array containing the same values as those in an existing array segment but in reverse order. Here is a method that does that:

/* Returns a new array whose elements are those in the specified array ** segment (a[low..high)) but in reverse order. ** pre: 0 <= low <= high <= a.length */ public static int[] reverseOf(int[] a, int low, int high) { final int N = high - low; // length of array to be returned. int[] result = new int[N]; // create array to be returned // loop invariant: result[0..i-1] contains the elements in a[high-i..high-1] // in reverse order. for (int i=0; i != N; i = i+1) { // Fill new array result[i] = a[high-1-i]; } return result; } |

In case you don't appreciate the difference between the effects of the
methods `reverse()` and `reverseOf()`, here is an example.
Suppose that we have an array `junk[]` as follows:

0 1 2 3 4 5 6 7 8 +----+----+----+----+----+----+----+----+----+ junk | 3 | 12 | 5 | -2 | 0 | 9 | 15 | -4 | 7 | +----+----+----+----+----+----+----+----+----+ |

Then making the call `ArrayExamples.reverse(junk, 1, 7)`
(here we're assuming that the `reverse()` method is in the
`ArrayExamples` class) will have the effect of reversing
the order of the values occupying `junk[1..6]` so that it
looks like this:

0 1 2 3 4 5 6 7 8 +----+----+----+----+----+----+----+----+----+ junk | 3 | 15 | 9 | 0 | -2 | 5 | 12 | -4 | 7 | +----+----+----+----+----+----+----+----+----+ |

On the other hand, the call `ArrayExamples.reverseOf(junk, 1, 7)`
will leave the contents of `junk[]` undisturbed but will create,
and return a reference to, a new array like this:

0 1 2 3 4 5 +----+----+----+----+----+----+ | 15 | 9 | 0 | -2 | 5 | 12 | +----+----+----+----+----+----+ |

Of course, the client would not have called the method in the first place unless it wanted to make use of the resulting array, so typically (but not always) such a call would occur on the right-hand side of an assignment statement. Typical client code might be like this:

This would assign to `garbage` a reference to the array shown
above.
This assumes, of course, that `garbage` has been declared to
be a variable of type `int[]`.