Funzione ricorsiva

Gianni911
Ragazzi ho un esercizio in cui devo disegnare un "<" con gli asterichi,con una funzione ricorsiva..
Ho qualche problema nella risoluzione,qualcuno sa come possso fare??
Vi posto il codice,ciò che ho fatto..
void stampamin(int N,int l=0,int k=0){
                              if(N==0)return;
                              if(l<N/2){
                                        for(int i=0;i<N/2-k+1;i++)cout<<" ";
                                        cout<<"*"<<endl;
                                        }
                              else{ 
                                   for(int i=0;i<k-N/2;i++)cout<<" ";
                                   cout<<"*"<<endl;
                                   }
                              return stampamin(N-1,l+1,k+1);
                             }

Grazie!!

Risposte
hamming_burst
ma la tua funzione stampa solo spazi e asterischi in linea retta (mi sembra).
per risolvere il tuo problema io utilizzere i semplici caratteri speciali del vetusto ma grande codice ASCII (ritorno carrello, tab, ecc...)
- portarti a distanza di tot spazi (utilizzi tab orizzontale)
- inizi a stampare asterischi ricorsivamente, stampando insieme ritorno carrello e ritorno a capo.
questo per /
poi ripeti nell'altro senso stampi in senso contrari e qua invece usi spazio e stamperai \.

prova a scriverlo in codice :-)

EDIT:
ragionamento a ciclo, sbagliato per questo problema.

Gianni911
Mah che stampa una linea fortunatamente no :D
Questo é quello che ottengo compilando quel codice.



Riguardo il metodo da te citato non credo di aver capito,esattamente cosa dovrei fare.
Anche io uso il ritorno carrello é gli spazi bianchi
Grazie

apatriarca
Quando si richiama un metodo ricorsivo esistono due fasi, una discendente e una ascendente (i nomi me li sto inventando al momento ma immagino ci siano dei termini più corretti che non ho modo di verificare adesso). Nella fase discendente il metodo viene richiamato fino ad arrivare al caso base, mentre in quella ascendente si utilizzano i risultati ottenuti dalle chiamate ricorsive per fare ulteriore lavoro. Invece di fare lavoro solo in una delle due fasi (normalmente quella discendente), è nel tuo caso più conveniente farlo in entrambe (in altri casi e altri linguaggi è invece conveniente farlo nella fase discendente in modo da trasformarlo in un ciclo). La funzione che stampa il '<' avrebbe più o meno l'aspetto seguente:
if n == 0
    stampa *
else
    stampa n spazi
    stampa *
    richiama metodo con n-1
    stampa n spazi
    stampa *

Gianni911
Grazie adesso ci provo,avresti qualche buon libro in riguardo questo tipo di ricorsioni(in mezzo)??oppure anche dispense da consigliarmi..
Grazie.

hamming_burst
@Gianni91:
uuh lascia stare ciò che ho scritto.
Ho completamente saltato la parola "ricorsiva"... Ho ragionato con un semplice ciclo, chiedo venia :roll:

Gianni911
no problem...
qualche idea ricorsiva?? :D

apatriarca
Non credo che ci siano libri che spiegano questa idea, non essendo per niente diversa da quella della normale ricorsione. Viene in effetti usata spesso. Considera per esempio la definizione ricorsiva del fattoriale:
\[
\begin{cases}
0\,! = 1 \\
n\,! = (n-1)\,! \, n \\
\end{cases}
\]
In quella che ho chiamato la fase discendente si decrementa il numero n per poi richiamare il fattoriale e in quella ascendente si moltiplica il fattoriale di \(n-1\) con \(n\). Altri esempi più simili a questo si incontrano in alcuni algoritmi sugli alberi (ma non sono certo che tu abbia studiato gli alberi).

Per mettere alla prova la mia versione ho implementato il seguente breve programma in haskell.
stampamin n | n == 0 = return ()
            | n == 1 = putStrLn "*"
            | n > 1  = do
                let riga = replicate (div (n-1) 2) ' ' ++ "*"
                putStrLn riga
                stampamin (n-2)
                putStrLn riga
            | True   = error "n deve essere un numero positivo."

main = stampamin 5

Eseguendolo ottengo
  *
_*
*
_*
  *

Sostituendo il 5 nel main con un 6 ottengo invece
  *
_* 
*
*
_*
  *

Nota che in realtà è tutto ricorsivo in questa versione essendo ricorsive anche le funzioni replicate (che crea una lista lunga come il primo argomento e contenenti copie del secondo - in haskell non ci sono parentesi intorno ai parametri delle funzioni..), sia l'operatore ++ che serve per concatenare due liste (in questo caso due stringhe).

P.S. C'è uno strano bug nella visualizzazione dei risultati nel forum e ho dovuto aggiungere i _ che non sono presenti nell'output originale. In caso contrario non mi stampava gli spazi.

Gianni911
Innanzitutto grazie per la spiegazione cosi completa,
riguardo il codice.Il comando "putStrLn",é del c,perché io ho fatto c++,dovrebbe essere il cout ???
Perché non vedo nessuna funzione con quel nome.. :D

apatriarca
putStrLn è una funzione standard in haskell che stampa una stringa a video e va a capo. Corrisponde alla funzione puts del C, ma può essere "simulata" utilizzando iostream aggiungendo << endl dopo aver stampato la stringa. Ma in C++, la parte del codice che stampa la stringa con gli spazi e l'asterisco l'avrei implementata con un ciclo (o con una corrispondente funzione ricorsiva). In effetti, è possibile che il codice macchina generato da quel codice haskell corrisponda al ciclo che stampa i singoli caratteri uno per volta (in haskell il codice subisce trasformazioni più radicali che in C++ essendo molto più astratto). Avrei insomma scritto (manca il codice intorno con i vari if):
int nzeri = (n-1)/2;
for (int i = 0; i < nzeri; ++i) cout << ' ';
cout << '*' << endl;

stampamin(n-2);

for (int i = 0; i < nzeri; ++i) cout << ' ';
cout << '*' << endl;

Gianni911
Perfetto,capito..
Adesso ci ragiono un pò su questa funzione.
Grazie per l'aiuto :D

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.