/* RecursiveListUtils.java ** An instance of this class has several methods providing utilities for ** recursive lists (i.e., instances of classes implementing the RecursiveList ** interface). */ public class RecursiveListUtils { private int callCntr; // to count method calls // Resets the call counter to zero. public void resetCounter() { callCntr = 0; } // Returns the value of the call counter. public int getCounter() { return callCntr; } /* Returns the length of (i.e., # of elements in) the given list. */ public int lengthOf(RecursiveList list) { callCntr++; if (list.isEmpty()) { return 0; } else { return 1 + lengthOf(list.tailOf()); } } /* Returns a recursive list whose elements are those in the given ** array, and in the same order. The second parameter is for the ** purpose of providing a "factory" (i.e., a means of creating a new ** (empty) list). */ public RecursiveList listify(T[] a, RecursiveList factory) { RecursiveList result = factory.emptyList(); //System.out.println("Upon creating empty list, have: " + result); // Place array elements into the list from the end of the array // to the beginning. for (int i = a.length; i != 0; i--) { result = result.cons(a[i-1]); //System.out.println("After inserting " + a[i-1] + " have " + result); } callCntr = callCntr + a.length; return result; } public T[] arrayify(RecursiveList list) { T[] result = (T[])(new Object[lengthOf(list)]); for (int i=0; i != result.length; i++) { result[i] = list.headOf(); list = list.tailOf(); } callCntr = callCntr + 2*result.length; return result; } /* Returns true iff some element in the given list is equal to the ** given item (according to item's equals() method). */ public boolean occursIn(T item, RecursiveList list) { if (list.isEmpty()) { return false; } else { return item.equals(list.headOf()) || occursIn(item, list.tailOf()); } } /* Returns the list that results from appending the second given list ** to the end of the first one. */ public RecursiveList append(RecursiveList first, RecursiveList second) { callCntr++; if (first.isEmpty()) { return second; } else { // Recursively append the second list onto the end of the first // one's tail and then insert the first one's head! RecursiveList allButHead = append(first.tailOf(), second); return allButHead.cons(first.headOf()); } } /* Returns a list containing the same elements as the given one, but ** in reverse order. */ public RecursiveList reverse(RecursiveList list) { callCntr++; if (list.isEmpty()) { return list; } else { RecursiveList justHead = list.emptyList().cons(list.headOf()); return append(reverse(list.tailOf()), justHead); } } /* This is a more efficient version of the method above. */ public RecursiveList reverse2(RecursiveList list) { callCntr++; return reverse2Aux(list, list.emptyList()); } /* Auxiliary to the method above, this one returns the list obtained ** by appending the reverse of 'yetToBeRev' onto the end of 'alreadyRev'. ** The parameter names are meant to suggest that this method "expects" ** to receive, in 'yetToBeRev', an intact suffix of the list whose ** reverse is to be constructed and, in 'alreadyRev', the already-reversed ** complementary prefix of that list. ** ** The technique employed here is that of the "accumulating parameter", ** in which one of the method's parameters serves as a partial result ** and is augmented as the recursive calls go deeper and deeper. When ** the base case is reached, the accumulating parameter is the desired ** result (or at least the desired result can be obtained from it ** relatively easily). Here, the accumulating parameter is 'alreadyRev'. */ private RecursiveList reverse2Aux(RecursiveList yetToBeRev, RecursiveList alreadyRev) { callCntr++; if (yetToBeRev.isEmpty()) { return alreadyRev; } else { return reverse2Aux(yetToBeRev.tailOf(), alreadyRev.cons(yetToBeRev.headOf())); } } }