|
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
|