31C. Another Example: Membership Test
Let's use equations to define function member(x, L), which
is true if x belongs to list L. For example,
|
member(3, [2, 6, 3, 5]) |
= |
true |
|
member(4, [2, 6, 3, 5]) |
= |
false |
Two equations will do, one for an empty list and one for a nonempty list.
Operator or is the logical or
operator, the same as | | in C++.
The following equations are true for all integers x and lists L.
(member.1) |
member(x, [ ]) |
= |
false |
|
(member.2) |
member(x, L) |
= |
head(L) ==
x or member(x,
tail(L)) |
(when L ≠ [ ]) |
The first equation should be clear. The empty list does
not have any members. Let's try some examples of the second
equation, (member.2). According to that equation,
|
member(6, [2, 4, 6, 8]) |
|
= member(6, 2 : [4, 6, 8]) |
|
= 6 == 2 or member(6, [4, 6, 8]) |
|
= false or true |
|
= true |
(Remember the rule for hand-simulating recursive algorithms.
Recursive calls are assumed to work correctly. You can do the
same for checking equations.)
|
|
member(2, [2, 4, 6, 8]) |
|
= member(2, 2 : [4, 6, 8]) |
|
= 2 == 2 or member(2, [4, 6, 8]) |
|
= true or member(2, [4, 6, 8]) |
|
= true |
Notice that we do not need to evaluate member(2, [4, 6, 8])
because (true or x) is true regardless of what x is.
This is a search problem,
and the algorithm does not need
to look at the entire list when the it finds what it is looking for.
|
|
member(5, [2, 4, 6, 8]) |
|
= member(5, 2 : [4, 6, 8]) |
|
= 5 == 2 or member(5, [4, 6, 8]) |
|
= false or false |
|
= false |
|
Let's convert Equations (member.1) and (member.2) into a definition
of member in C++.
bool member(int x, const ListCell* L)
{
if(L == NULL)
{
return false;
}
else
{
return x == L->head || member(x, L->tail);
}
}
Notice that, for both length and member, we wrote one
equation for an empty list and one for a nonempty list.