|
A nondestructive method on a linked list is one that does not change the list. A simple example is a method to compute the length of a linked list. We can use either a loop or recursion.
A recursive solution makes use of two facts.
static int length(List L) { if(isEmpty(L)) { return 0; } else { return = 1 + length(tail(L)); } }
A looping definition of length is based on the following table showing computation of length(L) where L = [2,4,6,8].
rest | num |
---|---|
[2,4,6,8] | 0 |
[4,6,8] | 1 |
[6,8] | 2 |
[8] | 3 |
[ ] | 4 |
Notice that, at every line, length(L) = num + length(rest). That is, assertion
length(L) = num + length(rest)is an invariant for the loop. Clearly, when rest is [ ], lentth(L) = num.
static int length(List L) { int num = 0; for(List rest = L; !isEmpty(rest); rest = tail(rest)) { num++; } return num; }
Let's define method member(x,L), which returns true if x occurs in list L. For example, member(2, [2,4,6,8]) is true, but member(3, [2,4,6,8]) is false. This is an example of a search problem.
Let's start with a recursive definition. No number is a member of an empty list. A number x is a member of a nonempty list L just when either x is equal to the head of L or x is a member of the tail of L.
static boolean member(int x, List L) { if(isEmpty(L)) { return false; } else { return head(L) == x || member(x, tail(L)); } }
A looping method looks at each member of the list, asking it is equal to x.
static boolean member(int x, List L) { for(List rest = L; !isEmpty(rest); rest = tail(rest)) { if(x == head(rest)) { return true; } } return false; }
Let's write a method that takes a list L and returns a list of the even numbers in list L, in the same order as they occur in L. For example, evens([1,2,3,4,5,6] = [2,4,6].
Here is a thought process for defining evens(L).
If L is empty, then it does not contains any even numbers, so evens(L) = [ ].
If L begins with an odd number, then surely evens(L) = evens(tail(L)). For example, evens([1,2,3,4,5,6]) = evens([2,3,4,5,6]).
If L begins with an even number, then evens(L) is a list that begins with head(L), and evens(L) = head(L) : evens(tail(L)). For example,
evens([2,3,4,5,6]) = 2 : [4,6] = 2 : evens([3,4,5,6]).Replacing the : operator by the cons method, we see that evens(L) = cons(head(L), evens(tail(L))).
static List evens(List L) { if(isEmpty(L)) { return emptyList; } else if(head(L) % 2 == 0) { return cons(head(L), evens(tail(L))); } else { return evens(tail(L)); } }
Write a definition of static method copyList(L), which yields a copy of list L. (The copy is made of new list cells.)
AnswerWrite a definition of static method sum(L), where sum(L) returns the sum of all members of list L. For example, sum([2,3,4]) = 2 + 3 + 4 = 9. The sum of an empty list is 0. Answer
If L has length n, how long does it take to compute sum(L)? Use big-O notation to express the answer. Answer
Write a definition of static method smallest(L), which yields the smallest member of nonempty list L. For example, smallest([2,3,4]) = 2 and smallest([6,4,8,7]) = 4. Answer
Write a definition of static method prefix(L, n), which yields the length n prefix of list L. For example, prefix([2,4,6,8,10], 3) = [2,4,6]. If n is larger than the length of L then prefix(L, n) should return L. For example, prefix([2,4,6,8,10], 50) = [2,4,6,8,10]. Answer
|