Per spiegare la ricorsione , uso una combinazione di spiegazioni diverse, di solito per entrambi tentare di:
- spiegare il concetto,
- spiegare perché è importante,
- spiega come ottenerlo.
Per cominciare, Wolfram | Alpha lo definisce in termini più semplici di Wikipedia :
Un'espressione tale che ogni termine è generato ripetendo una particolare operazione matematica.
Matematica
Se il tuo studente (o la persona che spieghi anche tu, d'ora in poi dirò studente) ha almeno un background matematico, ovviamente hanno già incontrato la ricorsione studiando le serie e la loro nozione di ricorsività e la loro relazione di ricorrenza .
Un ottimo modo per iniziare è quindi dimostrare con una serie e dire che è semplicemente ciò che riguarda la ricorsione:
- una funzione matematica ...
- ... che si chiama per calcolare un valore corrispondente a un n-esimo elemento ...
- ... e che definisce alcuni confini.
Di solito, o ottieni un "huh huh, whatev '" nella migliore delle ipotesi perché ancora non lo usano, o più probabilmente solo un russare molto profondo.
Esempi di codifica
Per il resto, in realtà è una versione dettagliata di ciò che ho presentato nell'addendum della mia risposta per la domanda che hai sollevato riguardo ai puntatori (bad pun).
In questa fase, i miei studenti di solito sanno come stampare qualcosa sullo schermo. Supponendo che stiamo usando C, sanno come stampare un singolo carattere usando write
o printf
. Conoscono anche i circuiti di controllo.
Di solito ricorro ad alcuni problemi di programmazione ripetitivi e semplici fino a quando non lo ottengono:
- l' operazione fattoriale ,
- una stampante alfabetica,
- una stampante alfabetica invertita,
- l' operazione di esponenziale .
Fattoriale
Il fattoriale è un concetto matematico molto semplice da capire e l'implementazione è molto vicina alla sua rappresentazione matematica. Tuttavia, all'inizio potrebbero non capirlo.
alfabeti
La versione alfabetica è interessante per insegnare loro a pensare all'ordinamento delle loro dichiarazioni ricorsive. Come con i puntatori, ti lanceranno semplicemente delle linee in modo casuale. Il punto è portarli a rendersi conto che un ciclo può essere invertito modificando le condizioni OPPURE invertendo semplicemente l'ordine delle istruzioni nella tua funzione. Ecco dove la stampa dell'alfabeto aiuta, poiché è qualcosa di visivo per loro. Basta far scrivere a loro una funzione che stamperà un carattere per ogni chiamata e si chiamerà in modo ricorsivo per scrivere quello successivo (o precedente).
Fan FP, salta il fatto che stampare elementi sul flusso di output è un effetto collaterale per ora ... Non diventiamo troppo fastidiosi sul fronte FP. (Ma se usi una lingua con il supporto dell'elenco, sentiti libero di concatenare un elenco ad ogni iterazione e semplicemente stampare il risultato finale. Ma di solito li avvio con C, che purtroppo non è il migliore per questo tipo di problemi e concetti) .
elevamento a potenza
Il problema esponenziale è leggermente più difficile ( in questa fase dell'apprendimento). Ovviamente il concetto è esattamente lo stesso di un fattoriale e non c'è complessità aggiunta ... tranne per il fatto che hai più parametri. E questo di solito è abbastanza per confondere le persone e buttarle via all'inizio.
La sua forma semplice:
può essere espresso in questo modo dalla ricorrenza:
Più forte
Una volta che questi semplici problemi sono stati mostrati E reimplementati nei tutorial, puoi dare esercizi leggermente più difficili (ma molto classici):
- I numeri di Fibonacci ,
- Il più grande divisore comune ,
- Il problema delle 8 regine ,
- Il gioco delle torri di Hanoi ,
- E se si dispone di un ambiente grafico (o è possibile fornire stub di codice per esso o per un output terminale o possono già gestirlo), cose come:
- E per esempi pratici, considera la scrittura:
- un algoritmo di attraversamento di alberi,
- un semplice parser di espressioni matematiche,
- un gioco dragamine.
Nota: di nuovo, alcuni di questi non sono affatto più difficili ... Si limitano ad affrontare il problema esattamente dalla stessa angolazione, o leggermente diversa. Ma la pratica rende perfetti.
Helpers
Un riferimento
Alcune letture non fanno mai male. Bene all'inizio, e si sentiranno ancora più persi. È il genere di cose che cresce su di te e che rimane nella parte posteriore della testa fino a quando un giorno ti accorgi di averlo finalmente ottenuto. E poi ripensi a queste cose che leggi. La ricorsione , la ricorsione in Informatica e le pagine di relazione di ricorrenza su Wikipedia farebbero per ora.
Livello / profondità
Supponendo che i tuoi studenti non abbiano molta esperienza di programmazione, fornisci stub di codice. Dopo i primi tentativi, assegnare loro una funzione di stampa in grado di visualizzare il livello di ricorsione. La stampa del valore numerico del livello aiuta.
Il diagramma Stack-as-Drawers
Anche il rientro di un risultato stampato (o dell'output del livello) aiuta, poiché fornisce un'altra rappresentazione visiva di ciò che il programma sta facendo, aprendo e chiudendo contesti di stack come i cassetti o le cartelle in un esploratore del file system.
Acronimi ricorsivi
Se il tuo studente è già un po 'esperto nella cultura del computer, potrebbe già utilizzare alcuni progetti / software con nomi che utilizzano acronimi ricorsivi . È una tradizione che va in giro da qualche tempo, specialmente nei progetti GNU. Alcuni esempi includono:
Ricorsivo:
- GNU - "GNU's Not Unix"
- Nagios - "Nagios non vuole insistere sulla santità"
- PHP - "PHP Hypertext Preprocessor" (e originariamente "Personal Home Page")
- Vino - "Il vino non è un emulatore"
- Zile - "Zile Is Lossy Emacs"
Reciprocamente ricorsivo:
- HURD - "HIRD of Unix-Replacing Daemons" (dove HIRD è "HURD of Interfaces che rappresenta Depth")
Fagli provare a inventare il loro.
Allo stesso modo, ci sono molte occorrenze di umorismo ricorsivo, come la correzione ricorsiva della ricerca di Google . Per ulteriori informazioni sulla ricorsione, leggi questa risposta .
Insidie e ulteriore apprendimento
Alcuni problemi con cui le persone di solito lottano e per i quali è necessario conoscere le risposte.
Perché, oh Dio, perché ???
Perché dovresti farlo? Un motivo valido ma non ovvio è che spesso è più semplice esprimere un problema in questo modo. Una ragione non così buona ma ovvia è che spesso ci vuole meno battitura a macchina (non farli sentire veramente l33t solo per usare la ricorsione però ...).
Alcuni problemi sono sicuramente più facili da risolvere quando si utilizza un approccio ricorsivo. In genere, qualsiasi problema che è possibile risolvere utilizzando un paradigma Divide and Conquer si adatta a un algoritmo di ricorsione multi-ramificato.
Cosa c'è di nuovo N ??
Perché il mio n
o (qualunque sia il nome della tua variabile) ogni volta è diverso? I principianti di solito hanno un problema a capire cosa sono una variabile e un parametro e come le cose nominate n
nel tuo programma possono avere valori diversi. Quindi ora se questo valore è nel circuito di controllo o ricorsione, è ancora peggio! Sii gentile e non usare gli stessi nomi di variabili ovunque, e chiarisci che i parametri sono solo variabili .
Condizioni finali
Come posso determinare la mia condizione finale? È facile, basta far loro dire i passi ad alta voce. Ad esempio per il fattoriale iniziare da 5, quindi 4, quindi ... fino a 0.
Il diavolo è nei dettagli
Non parlare con cose precoci come l' ottimizzazione delle chiamate di coda . Lo so, lo so, il TCO è carino, ma all'inizio non gliene importa. Concedi loro un po 'di tempo per avvolgere la testa attorno al processo in un modo che funzioni per loro. Sentiti libero di frantumare il loro mondo più tardi, ma concedi loro una pausa.
Allo stesso modo, non parlare direttamente dalla prima lezione dello stack di chiamate e del suo consumo di memoria e ... beh ... lo stack trabocca . Spesso insegno agli studenti privatamente che mi mostrano lezioni in cui hanno 50 diapositive su tutto ciò che c'è da sapere sulla ricorsione quando riescono a malapena a scrivere correttamente un ciclo in questa fase. Questo è un buon esempio di come un riferimento ti aiuterà più tardi, ma in questo momento ti confonde profondamente.
Ma per favore, a tempo debito, chiarisci che ci sono ragioni per percorrere la strada iterativa o ricorsiva .
Ricorsione reciproca
Abbiamo visto che le funzioni possono essere ricorsive e persino che possono avere più punti di chiamata (8 regine, Hanoi, Fibonacci o persino un algoritmo di esplorazione per un dragamine). Ma che dire delle chiamate reciprocamente ricorsive ? Inizia anche qui con la matematica. f(x) = g(x) + h(x)
dove g(x) = f(x) + l(x)
e h
e l
solo fare cose.
Iniziare con solo serie matematiche semplifica la scrittura e l'implementazione poiché il contratto è chiaramente definito dalle espressioni. Ad esempio, le sequenze maschili e femminili di Hofstadter :
Tuttavia, in termini di codice, è da notare che l'implementazione di una soluzione reciprocamente ricorsivo spesso porta alla duplicazione del codice e dovrebbe piuttosto essere semplificato in una singola forma ricorsiva (Vedere Peter Norvig s' Solving Ogni Sudoku Puzzle .