Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #158252
| Path | csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail |
|---|---|
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
| Newsgroups | comp.lang.c |
| Subject | Re: Recursion v Memoization |
| Date | Thu, 07 Jan 2021 06:37:39 -0800 |
| Organization | A noiseless patient Spider |
| Lines | 143 |
| Message-ID | <86pn2gq0cs.fsf@linuxsc.com> (permalink) |
| References | <rsg72i$eq4$1@gioia.aioe.org> <861rf6uzw4.fsf@linuxsc.com> <1b1rf2zsuf.fsf@pfeifferfamily.net> <86h7nwrq8s.fsf@linuxsc.com> <1br1mzoymv.fsf@pfeifferfamily.net> |
| Mime-Version | 1.0 |
| Content-Type | text/plain; charset=us-ascii |
| Injection-Info | reader02.eternal-september.org; posting-host="c154dc4d172b443324888acc44505703"; logging-data="28893"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/bIdsjZjzQ4VoTUrwsAttvfN3uG6KZm0E=" |
| User-Agent | Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) |
| Cancel-Lock | sha1:1T1hrde1U/we97x1MbeWxLcgIug= sha1:k68kapq23v++WubLItSatN0UXdA= |
| Xref | csiph.com comp.lang.c:158252 |
Show key headers only | View raw
Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes:
> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>
>> Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes:
>>
>>> Recursive Fibonacci is actually a great function to go through in a
>>> beginning programming class, because you can use it to show
>>>
>>> (1) how recursion works. By the time the students have Fibonacci
>>> working recursively, they're got at least an inkling of the
>>> process.
>>>
>>> (2) why recursion can be *horrible* choice for a solving a problem.
>>> It was even better for this back in the days of 386s and the
>>> like, because you could have a call that went for several
>>> minutes but eventually came back with the right answer.
>>>
>>> (3) how to use a static array to add memoization to a recursive
>>> function to get something of the best of both worlds.
>>
>> I don't find these reasons persuasive. Computing fibonacci
>> through double recursion is not an obvious algorithm but it is
>> obviously a dumb algorithm. The lesson is not that recursion
>> is horrible but that bad algorithms are horrible, which in turn
>> removes the motivation for memoization, because it isn't really
>> necessary here. (In fact I'm not sure where it is necessary,
>> but that's a separate discussion.)
>
> A lot of students have a really hard time seeing a function as something
> other than two jumps -- they trace their code as if they were taking a
> jump to the start of the function, and then the return is another jump.
> Talk all you want about encapsulation, parameters, abstraction... to
> the new student those are just extra complexities the professor is
> layering on the two jumps. Recursive factorial starts to get them away
> from the mindset (I used to conduct an exercise in class where I'd hand
> a number to the first student in the row, they'd pass n-1 to the student
> on their left, they'd pass n-2 to the next student... then the student
> who got "1" would return it to the student on their right, who would
> pass "2" to the next student, and so forth).
That's a good exercise. As it happens I used a similar exercise
(but not about recursion or factorial) many years ago when
teaching a programming class.
> But that still doesn't
> really break them of it when they're writing their code. By the time
> they've got Fibonacci working, though, they *have* to be thinking in
> terms of passing (n-1) and (n-2) to the function and getting the answers
> back. It's just too hard to trace the execution without it.
Having there be two recursive calls is significant. I may have
a better example problem for that - see below.
>> Teaching recursion should start first with single recursion, with
>> a good choice being the familiar problem of greatest common
>> divisor.
>
> Fibonacci is typically the second one. GCD is another good first one.
It's good to hear we agree on the main point. At first I thought
you meant start off with Fibonacci.
>> If one then wants to give naive recursive fibonacci as
>> a bad example, fine, but it isn't the right place to start. And,
>> if recursive fibonacci /is/ given as a bad example, it should be
>> closely followed by an example of double recursion where the
>> recursion helps rather than hurts. Two possible choices for that
>> are merge sort (naturally recursive) or computing factorials of
>> large numbers (where subdividing recursion isn't obvious but
>> gives a huge speedup over the more obvious iterative algorithm).
>
> Mergesort would probably be a good third one. It's got stuff going on
> you need to think about other than just how the recursion works.
In light of this additional information, let me offer a more
refined set of suggestions.
Start with GCD. That will get the students used to the form of
recursion, even if some of them will not yet understand it.
Next do factorial, but actually three different factorials.
First the obvious one:
unsigned
factorial_one( unsigned n ){
return n < 2 ? 1 : n * factorial_one( n-1 );
}
Second, a version that transforms the first version into a two
argument form so that tail recursion can be used:
static unsigned factorial_times( unsigned, unsigned );
unsigned
factorial_two( unsigned n ){
return n < 2 ? 1 : factorial_times( n, 1 );
}
unsigned
factorial_times( unsigned n, unsigned m ){
return n < 2 ? m : factorial_times( n-1, n*m );
}
Third, a different approach using subdivision, which gives two
recursive calls rather than just one:
static unsigned times_from_to( unsigned k, unsigned n );
/* product of integers i with k <= i < n */
unsigned
factorial_three( unsigned n ){
return n < 2 ? 1 : times_from_to( 1, n+1 );
}
static unsigned
times_from_to( unsigned k, unsigned n ){
unsigned delta = n-k;
unsigned m = k + delta/2;
return delta < 2 ? k : times_from_to( k, m ) * times_from_to( m, n );
}
(As mentioned above the point of this approach is for cases where
multiple precision arithmetic is being used, so that when two
numbers are multiplied they have similar magnitudes, which makes
the computation go a lot faster.)
After the three factorials, fibonacci, if that is thought
necessary. (I'm undecided about that.)
For the last example, not mergesort, but the Chinese Ring puzzle.
The problem is pretty much inherently recursive (I don't see any
obvious way to turn it into an iteration). Also it uses mutual
recursion, with 'ring_on()' and 'ring_off()' each calling the
other. Furthermore it gives an exponential cost because the
problem itself is exponential. (I didn't think up this example
myself but heard it from Professor Don Stanat, if I remember
right.) I'm sure there are other good examples of problems that
use mutual recursion, but offhand I can't think of one that is
not amenable to being turned into an iteration.
So, fwiw, there are some ideas.
Back to comp.lang.c | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
Recursion v Memoization Real Troll <real.Troll@trolls.com> - 2020-12-29 16:30 -0500
Re: Recursion v Memoization Bart <bc@freeuk.com> - 2020-12-29 22:17 +0000
Re: Recursion v Memoization Ike Naar <ike@sdf.org> - 2020-12-30 05:47 +0000
Re: Recursion v Memoization Bart <bc@freeuk.com> - 2020-12-30 11:55 +0000
Re: Recursion v Memoization "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2020-12-29 21:51 -0800
Re: Recursion v Memoization Tim Rentsch <tr.17687@z991.linuxsc.com> - 2020-12-31 00:46 -0800
Re: Recursion v Memoization David Brown <david.brown@hesbynett.no> - 2020-12-31 16:12 +0100
[OT] was: Recursion v Memoization Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-01-01 15:59 +0000
Re: [OT] was: Recursion v Memoization David Brown <david.brown@hesbynett.no> - 2021-01-01 17:35 +0100
Re: [OT] was: Recursion v Memoization Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-01-01 08:40 -0800
Re: [OT] was: Recursion v Memoization Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-01-02 10:36 -0800
Re: [OT] was: Recursion v Memoization "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-01-02 16:59 -0800
Re: [OT] was: Recursion v Memoization "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-01-02 17:00 -0800
Re: Recursion v Memoization Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2021-01-02 18:56 -0700
Re: Recursion v Memoization Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-01-04 19:56 -0800
Re: Recursion v Memoization beej@beej.us (Beej) - 2021-01-05 04:27 +0000
Re: Recursion v Memoization Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-01-07 04:54 -0800
Re: Recursion v Memoization beej@beej.us (Beej) - 2021-01-11 05:43 +0000
Re: Recursion v Memoization Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-01-11 06:34 -0800
Re: Recursion v Memoization Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2021-01-05 14:35 -0700
Re: Recursion v Memoization Real Troll <real.troll@trolls.com> - 2021-01-05 16:45 -0500
Re: Recursion v Memoization Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2021-01-05 15:33 -0700
Re: Recursion v Memoization Jorgen Grahn <grahn+nntp@snipabacken.se> - 2021-01-06 09:40 +0000
Re: Recursion v Memoization Jorgen Grahn <grahn+nntp@snipabacken.se> - 2021-01-06 17:09 +0000
Re: Recursion v Memoization Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-01-07 06:37 -0800
Re: Recursion v Memoization Andrey Tarasevich <andreytarasevich@hotmail.com> - 2020-12-31 02:33 -0800
csiph-web