1. More complicated examples on arrays
Rearranging elements, Boolean inputs
Example: Write a method partitionArray(numbers, labels) which takes as input
an array of numbers and an array of TRUE/FALSE labels that represent which
items to keep and which items to discard.
The method returns a new array that first has all items labeled TRUE and then
those labeled FALSE.
For example,
// one-line test
printArray( partitionArray( new double[]{ 4, 7, 8, 6, 2, 5, 0, 1, 3, 9 }, new boolean[]{ F, T, T, F, T, F, F, T, F, F } ) ); // should be: true/false
// displays 7, 8, 2, 1, 9, 3, 0, 5, 6, 4
// multi-line test
double[] numbers = { 4, 7, 8, 6, 2, 5, 0, 1, 3, 9 };
double[] labels = { F, T, T, F, T, F, F, T, F, F } ) ); // should be: true/false
printArray( partitionArray( numbers, labels ) );
// displays 7, 8, 2, 1, 9, 3, 0, 5, 6, 4
The idea here is to fill the "true" items from the beginning of the result array
and the "false" items from the end of the result array:
j k
|...> <...|
_V______________________________________V__
result array: |___true section__|_________false section___|
This is similar to repeatElements. We need two separate indices to indicate an
available cell within the two sections. Based on the label we store a value in the
corresponding section and update the respective index.
double[] partitionArray( double[] numbers, boolean[] labels )
{
double[] result = new double[ numbers.length ];
int j = 0; // first empty cell in keep/true section
int k = numbers.length - 1; // first empty cell in ignore/false section
for ( int i = 0 ; i < labels.length ; i = i + 1 )
{
if ( labels[ i ] == true )
{
result[ j ] = numbers[ i ]; // label is true, so put item in "keep" section
j = j + 1; // move "keep index" to next cell on the right
}
else
{
result[ k ] = numbers[ i ]; // label must be false, so put item in "ignore" section
k = k - 1; // move "ignore index" to next cell on the left
}
}
return result;
}
Here is a version with while loop. To come up with the loop condition we notice that
* j and k start at the opposite ends of the result array
* j and k move towards each other as we transfer one item at a time
This suggests that whenever j and k are separated and j is before k, i.e. j < k, we have work to do.
We have to be careful to consider the case when j and k are on the same cell, i.e. should we have:
* while ( j < k )
* while ( j <= k )
It turns out that the correct condition is the second one, j <= k. To see this, try running the code
with small arrays, say of size 2 (or even of size 1) and see what happens.
double[] partitionArray( double[] numbers, boolean[] labels )
{
double[] result = new double[ numbers.length ];
int i = 0; // to access cells in the given arrays
int j = 0; // first empty cell in keep/true section
int k = numbers.length - 1; // first empty cell in ignore/false section
while ( j <= k )
{
if ( labels[ i ] == true )
{
result[ j ] = numbers[ i ]; // label is true, so put item in "keep" section
j = j + 1; // move "keep index" to next cell on the right
}
else
{
result[ k ] = numbers[ i ]; // label must be false, so put item in "ignore" section
k = k - 1; // move "ignore index" to next cell on the left
}
i = i + 1; // always moves so that we get to inspect a new original item
}
return result;
}
Swapping elements based on a list of indices
Example: Write a method swapElements(numbers, indices) which takes as input
an array of numbers and an array whose elements represent pairs of indices of
the first array.
The method swaps every pair of elements indicated by the corresponding indices.
For example,
_______________________________________
double[] testArray = {10, 15, 18, 12, 17, 16, 19, 13}; |_10_|_15_|_18_|_12_|_17_|_16_|_19_|_13_|
double[] indices = {4, 0, 3, 2, 5 7}; 0 1 2 3 4 5 6 7
\ \___/ / \_________/
\_______________/
// has to be multi-line test
swapElements(testArray, indices);
printArray(testArray); // displays 10 15 12 18 10 13 19 16
The new idea here is that values stored in one array are used as indices in another
array. However, the process overall is similar to previous methods -- we still
need to extract values from arrays and then use them as intended -- either as indices
or as values to be swapped.
Notice also the similarity with Fibonacci at the point of swapping values. We need to
create a temporary variable to avoid losing a value that has been overwritten.
Finally, there are two arrays and we need to decide which one to traverse with the loop.
It is fairly clear that traversing the actual values is not helpful -- we need to know
the indices of the values to be swapped, so we need to traverse the second array with the
loop.
double[] swapElements( double[] numbers, int[] indices )
{
for (int i = 0; i < indices.length; i = i + 2) // skip by 2 -- one pair at a time
{
int j = indices[ i ]; // extract a value from index array and treat it as an index in first array
int k = indices[ i + 1 ]; // extract the second index of the pair
double oldK = numbers[ k ]; // remember the previous value before overwriting it
numbers[ k ] = numbers[ j ]; // exchange the values ...
numbers[ j ] = oldK; // using the old value in second step
}
}