Introduction to Programming (CPSC 124)
—Hobart & William Smith Colleges, Fall 2014
Class Notes—October 10, 2014
Home | Syllabus | Calendar | Class Notes | Labs and Projects | General Notes |

Array Traversal Patterns

All array traversals are forms of counting loops. The number of times we run the loop is equal to the number of elements we want to visit in the array.

Suppose we have an array whose elements are of type T (that detail doesn't matter for traversals):

T[] arr = ... ; // How the array is created doesn't matter, either.

Ordinary Forward Traversal

int i = 0; 
while(i < arr.length)) {
    < At each iteration of the loop, we have access to arr[i] plus >
    < any elements we can access with calculations on i >
    
    i = i + 1;
}

It's common to use the (almost) equivalent for-loop form for traversals:

for (int i = 0; i < arr.length; i++) {
    < At each iteration of the loop, we have access to arr[i] plus >
    < any elements we can access with calculations on i >
}

For example, the following code fragment counts the number of elements greater than some threshold value:

double[] nums = ... ; double threshold = 10; int ct = 0; for (int i = 0; i < nums.length; i++) { if (nums[i] > threshold) { ct = ct + 1; } }

This code fragment moves every element in an array one index to the left (the original 0th value is discarded, while the last value is set to 0):

int[] xs = ... ; for (int i = 0; i < xs.length; i++) { if (i < xs.length - 1) { // only shift if we haven't reached the end xs[i] = xs[i+1]; } } xs[length-1] = 0;

Backwards Traversal

This one is exactly like forward traversal, except that we start at the last element, decrement the index, and stop when we reach the 0th:

for (int i = arr.length - 1; i >= 0; i--) {
    < At each iteration of the loop, we have access to arr[i] plus >
    < any elements we can access with calculations on i >
}

Here's a "shift right" fragment. Compare it with the left shift, above:

int[] xs = ... ; for (int i = xs.length-1; i >= 0; i--) { if (i > 0) { // only shift if we haven't reached the left end xs[i] = xs[i-1]; } } xs[0] = 0;

Partial Traversals

A partial traversal is just a traversal that begins and/or ands somewhere other than the 0th and arr.length - 1 indices. For example, we could have written our left and right shifts more simply as

for (int i = 0; i < xs.length - 1; i++) { xs[i] = xs[i+1]; } xs[length-1] = 0;
for (int i = xs.length-1; i > 0; i--) { xs[i] = xs[i-1]; } xs[0] = 0;

Hybrid Traversals

Forward, backward, and partial traversals can all be combined in any number of ways. We can even use versions of the terminating condition other than "i < arr.length" and "i >= 0". The key ingredient is that we are writing code to systematically visit some or all of the elements in an array exactly once.

As an extended example, here's a complete program that checks whether its input is a palindrome (i.e. a word that reads the same backwards and forwards. It only works with strings that have no punctuation, spaces, or mixed case in the letters. For example, it will report (incorrectly) that "Neil, a trap! Sid is part alien!" is not a palindrome (though it will work on "neilatrapsidispartalien"). It uses two ideas you have not seen before: the char data type (which holds a single character, rather than an entire String), and the use of the method toCharArray(), which, like equals() is available with every String. Since we're using index variables for both forward and backward traversal, we'll use the while-loop form here:

public class Palindrome { public static void main(String[] args) { String s = args[0]; char[] cs = s.toCharArray(); boolean pal = true; // A string with no characters is a palindrome int left = 0; int right = cs.length-1; // Note how the terminating condition makes this a *partial* traversal while(left <= right && pal) { if (cs[left] != cs[right]) { pal = false; } left += 1; right -= 1; } // while // Food for thought: if s is a palindrome, we will visit every element of // cs. However, the loop itself will only run for half as many iterations // as there are elements in cs. Why? System.out.print(s + " is "); if (!pal) { System.out.print("not "); } System.out.println("a palindrome"); } // main } // class Palindrome

Forward Traversal of Two-Dimensional Arrays

Suppose we have a two-dimensional array

T[][] B = ... ; // The specific type T and the way B is created don't matter.

Froward traversal of a two-dimensional array proceeds left-to-right, top-to-bottom. Really, it's just an ordinary forward traversal, but with a two-dimensional array, the element we get at each iteration is an entire row, and so we perform a traversal on that whole row before proceeding:

for (int i = 0; i < B.length; i++) {
    for (int j = 0; j < B[i].length; j ++) {
        < access to B[i][j] at each iteration >
    }
}

A good example of this comes from Project #3, at the point where you have to read each of the shuffle definitions. In class, we discussed this code fragment, which accomplishes the task:

Scanner inp = new Scanner(System.in); int n = inp.nextInt(); // number of shuffle definitions to read int[][] defns = new int[n][52]; for (int i = 0; i < defns.length; i++) { for (int j = 0; j < defns[i].length; j++) { // or you could use "j < 52" defns[i][j] = inp.nextInt(); } }

John Lasseter