recursion
Neil Cerutti
horpner at yahoo.com
Fri Sep 14 10:20:41 EDT 2007
On 2007-09-14, John Machin <sjmachin at lexicon.net> wrote:
> On Sep 14, 10:04 pm, Marc 'BlackJack' Rintsch <bj_... at gmx.net> wrote:
>> On Fri, 14 Sep 2007 13:40:17 +0200, Gigs_ wrote:
>> > sorry i think that i express wrong. having problem with english
>>
>> > what i mean is how python knows to add all thing at the end of recursion
>>
>> Because you have written code that tells Python to do so. ;-)
>>
>> > >>> def f(l):
>> > if l == []:
>> > return []
>> > else:
>> > return f(l[1:]) + l[:1]
>>
>> > f([1,2,3])
>>
>> > recursion1 f([2,3]) + [1]
>>
>> > recursion2 f([3]) + [2] or [2, 1]?
>>
>> > recursion3 f([]) + [3] or [3, 2, 1]
>>
>> Both alternatives in recursion 2 and 3 are wrong. You have to
>> simply replace the function invocation by its result which
>> gives:
>>
>> f([1, 2, 3])
>> r1 f([2, 3]) + [1]
>> r2 f([3]) + [2] + [1]
>> r3 f([]) + [3] + [2] + [1]
>> r4 [] + [3] + [2] + [1]
>>
>> And now the calls return:
>>
>> r3 [3] + [2] + [1]
>> r2 [3, 2] + [1]
>> r1 [3, 2, 1]
>>
>> > i dont get all this
>>
>> > >>> def f(l):
>> > if l == []:
>> > print l
>> > return []
>> > else:
>> > return f(l[1:]) + l[:1]
>>
>> > >>> f([1,2,3])
>> > []
>> > [3, 2, 1] # how this come here? how python save variables from each
>> > recursion?
>>
>> There is not just one `l` but one distinct `l` in each call.
>>
>
> I reckon that what the OP wants is a simple explanation of how
> function calls use a stack mechanism for arguments and local
> variables, and how this allows recursive calls, unlike the good ol'
> FORTRAN IV of blessed memory. Perhaps someone could oblige him?
>
> I'd try but it's time for my beauty sleep :-)
><yawn>
> Good night all
I may as well stick my neck out again, since I'm already
beautiful. ;)
Another way of understanding recursion is to break it up into
seperate functions, so the spectre of a function calling itself
doesn't appear.
def f(l):
if l == []:
return []
else:
return f(l[1:]) + l[:1]
The function above reverses a list of arbitrary length. To help
understand how it works, I'll write several discreet functions
that sort lists of fixed lengths.
I start with a simple case (though not the simplest case--that
only comes with experience), reversing a two-element list:
def f2(l): # reverse a two-element list
return [l[1], l[0]]
Next build up to the next level, writing a function that can
reverse a three-element list. The key is to be as lazy as
possible. You must figure out a way of taking advantage of the
function that reverses a two-element list. The obvious solution
is to use f2 to reverse the last two elements in our list, and
append the first element in the list to that result:
def f3(l): # reverse a three-element list
return f2(l[1:]) + l[:1]
And so on:
def f4(l):
return f3(l[1:]) + l[:1]
def f5(l):
return f4(l[1:]) + l[:1]
def f6(l):
return f5(l[1:]) + l[:1]
A definite pattern had emerged, and it should be apparent now how
to combine all those functions into one:
def f_(l):
if len(l) == 2:
return [l[1], l[0]]
else:
return f_(l[1:]) + l[:1]
But the function above breaks for lists with less than two items.
>>> f_([1])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f2
IndexError: list index out of range
We can handle that. The reverse of a zero or one-element list is
just itself.
def f_(l):
if len(l) < 2:
return l
elif len(l) == 2:
return [l[1], l[0]]
else:
return f_(l[1:]) + l[:1]
And we've arrived at an OK recursive function that can handle
arbitrary length lists. It's not as simple as it could be,
however. A little intuitive leap, perhaps, will allow you to note
that the case of a two-element list can actually be handled
without a special case:
def f(l):
if len(l) < 2:
return l
else:
return f(l[1:]) + l[:1]
Final note: for reasons of tradition, base cases are almost
always set up as it was in the original function, checking for a
zero-length list, and returning a new empty list, the truly
simplest base case. Another intuitive leap is possibly required
to note that a one-element list is not a special case after all:
it's a reverse of a zero-element list with that one element
appended.
def f(l):
if len(l) == 0:
return []
else:
return f(l[1:]) + l[:1]
Clear as mud?
--
Neil Cerutti
More information about the Python-list
mailing list