Joseph Haugh
University of New Mexico
IntList methods: addFirst() and middle()Last lecture we introduced head() and tail(). Today we add two more:
| Method | What it does |
|---|---|
addFirst(x) |
Returns a new list with x at the front |
middle() |
Returns a new list with the first and last elements removed |
addFirst(x) prepends x and returns a new list
IntList a = new IntList(); // [2, 3, 4]
a.add(2); a.add(3); a.add(4);
IntList b = a.addFirst(1); // [1, 2, 3, 4]
// a is still [2, 3, 4]Notice: add(x) appends to this list, addFirst(x) returns a new list
This makes addFirst natural for recursion: you build results on the way back up
public IntList addFirst(int x) {
IntList result = new IntList();
result.add(x);
for (int i = 0; i < size(); i++) {
result.add(get(i));
}
return result;
}
x in first, then copy every element of the original list after itmiddle() removes both the first and last element
IntList a = new IntList(); // [1, 2, 3, 4, 5]
a.add(1); a.add(2); a.add(3); a.add(4); a.add(5);
IntList m = a.middle(); // [2, 3, 4]
// a is still [1, 2, 3, 4, 5]A list of size 0 or 1 has no middle, so middle() throws an exception
A list of size 2 has an empty middle: [1, 2].middle() returns []
public IntList middle() {
if (size() < 2) {
throw new IllegalStateException("List must have at least 2 elements");
}
IntList result = new IntList();
for (int i = 1; i < size() - 1; i++) {
result.add(get(i));
}
return result;
}
1 and index size() - 2 (inclusive)0 (head) and index size() - 1 (last)boolean just as easily as inttrue and false can be combined with && and ||
allTrue(list) = list.head() && allTrue(list.tail())anyTrue(list) = list.head() || anyTrue(list.tail())true if every element is greater than 0[3, 7, 2, 5] all positive?
3 positive? Yes.[7, 2, 5] all positive? If so, then yes.truelist.head() > 0 and allPositive(list.tail())boolean allPositive(IntList list) {
}
boolean allPositive(IntList list) {
if (list.isEmpty()) {
return true; // base case: no elements to violate the rule
}
}
boolean allPositive(IntList list) {
if (list.isEmpty()) {
return true; // base case: no elements to violate the rule
}
return list.head() > 0 && allPositive(list.tail()); // recursive case
}
&& short-circuits and returns falsetrueboolean allPositive(IntList list) {
if (list.isEmpty()) return true;
return list.head() > 0
&& allPositive(list.tail());
}
allPositive([3, -1, 5])
= (3 > 0) && allPositive([-1, 5])
= true && allPositive([-1, 5])
= true && ((-1 > 0) && allPositive([5]))
= true && (false && ...)
= true && false
= false
-1, the && short-circuits5addFirstdoubleAll(list): return a new list with every element doubleddoubleAll([3, 7, 2])
= addFirst(6, doubleAll([7, 2]))
= addFirst(6, addFirst(14, doubleAll([2])))
= addFirst(6, addFirst(14, addFirst(4, doubleAll([]))))
= addFirst(6, addFirst(14, addFirst(4, []))) // base case
= [6, 14, 4]
IntList doubleAll(IntList list) {
}
IntList doubleAll(IntList list) {
if (list.isEmpty()) {
return new IntList(); // base case: empty in, empty out
}
}
IntList doubleAll(IntList list) {
if (list.isEmpty()) {
return new IntList(); // base case: empty in, empty out
}
IntList rest = doubleAll(list.tail()); // recursive case: handle the tail
return rest.addFirst(list.head() * 2); // prepend the doubled head
}
keepOrSkip(list):
base case: list is empty -> return empty list
recursive case:
result = keepOrSkip(list.tail()) // handle the rest
if we KEEP list.head():
return result.addFirst(list.head()) // put it at the front
else:
return result // skip it
isPalindrome(list) returns true if the list reads the same forwards and backwards[3, 1, 4, 1, 3]:
3, so they match[1, 4, 1] also a palindrome?size == ?1 and size == ?2 are always palindromeslist.head() equals list.get(list.size() - 1) (the last element)list.middle() is a palindromemiddle() peels off both ends at once, making the problem smallerremoveAll(list, target) returns a new list with all occurrences of target removedremoveAll([1, 2, 3, 2, 1], 2) = [1, 3, 1]
list.head() and removeAll(list.tail(), target)
list.head() == target, what do you return?list.head() != target, what do you return? (Hint: addFirst)isSorted(list) returns true if every element is <= the one after it[1, 3, 2, 4]. Is it sorted?
1 <= 3? Yes.[3, 2, 4] sorted? No, because 3 > 2.size == ?1 or size == ?2 is always sorted.list.tail().head() gives you the second element of listNew IntList methods
| Method | Effect |
|---|---|
addFirst(x) |
New list with x at front |
middle() |
New list without first and last |
Boolean recursion
&& or ||List-building recursion
new IntList()tail(), then addFirst the headKeep-or-skip pattern
addFirst or just return the result