DOMANDA Programmi con ricorsione C++

MPG

Utente Attivo
544
4
Ho iniziato la ricorsione è non è amore a prima vista...
Avrei questi 3 esercizi ma realmente sono in difficoltà potete darmi qualche spunto per favore?
1)int s(int n) restituisce la somma dei primi n numeri dispari
2)int f(int n) restituisce la somma dei primi n numeri naturali
3)bool pal(string t) stabilisce se la stringa t è palindroma.
 
Ultima modifica:

Aramen

Nuovo Utente
4
1
Ciao MPG,

partiamo dalla definizione di ricorsione, ovvero una "tecnica" basata sulla definizione induttiva (ricorsiva) di funzioni su domini che sono definiti in modo induttivo (ricorsivo). Nella scrittura del codice e in particolare nelle tipologie di algoritmi in cui sei poco confidente, una buona pratica è quella di definire preliminarmente l'algoritmo in pseudo-codice e poi successivamente tradurre nel tuo linguaggio.
Quindi prima di aiutarti consegnandoti le tre soluzioni, provo a darti qualche spunto per ragionare su alcuni esercizi e poi magari su alcuni di quelli che hai proposto.
Nella ricorsione è necessario quindi definire:
  • uno o più casi (passi) base per i quali il risultato può essere determinato direttamente
  • uno o più casi (passi) induttivi per i quali il calcolo del risultato si riconduce al calcolo della funzione ricorsiva su valori (o insiemi) più piccoli
Ad esempio la funzione fattoriale(n) restituisce 1 se n = 0, altrimenti restituisce n*fattoriale(n-1) se n > 0.

Quindi il mio consiglio è quello di definire e studiare prima di tutto l'algoritmo e dividere ognuna delle tue funzioni in caso/i base e caso/i induttivi.

Ragionando quindi sull'esercizio 3 che hai proposto e per fornirti un esempio "non numerico" ricorsivo possiamo definire ricorsivamente una stringa palindroma in tre casi:
  1. la stringa vuota è palindroma
  2. la stringa con un solo carattere è palindroma
  3. la stringa x y z è palindroma, se y è una stringa palindroma e x e z sono due caratteri uguali
Quindi l'algoritmo di risoluzione può essere visto come nel blocco di pseudo-codice seguente. Ovviamente quando vai ad implementare e tradurre nel tuo linguaggio, dovrai utilizzare i metodi offerti dalle librerie. Nel caso in cui i nomi dei metodi non siano chiari: s.length() ritorna la lunghezza della stringa s, s.charAt(x) ritorna il carattere in posizione x, s.substring(x,y) ritorna la sottostringa compresa negli indici x,y.
Quello che ho fatto è stato semplicemente tradurre i miei tre casi in pseudo-codice, in particolare il caso 1 lo trovi nell'istruzione condizionale IF, mentre il caso 2 e il caso 3 sono stati messi in AND all'interno della parte ELSE.

Codice:
boolean palindroma(String s) {
    boolean ris;
    IF (s.length() <= 1)
        ris = true;
    ELSE
        ris = (s.charAt(0) == s.charAt(s.length()-1)) && palindroma(s.substring(1,s.length()-1));
    return ris;
}

Ho allungato molto il brodo, ma essendo il tuo post poco esplicativo (non ho capito se stai approcciando alla ricorsione senza aver studiato un pochino di teoria oppure no) e per evitare di fornirti blocchi di codice da copiare e incollare e inutili al tuo apprendimento, ho tentato di darti una rapida e breve visione per magari fornirti la base su cui ragionare. Il mio consiglio è di partire dagli esercizi più semplici e andare a complicare via via, ma ricordandoti sempre di definire l'algoritmo in termini induttivi.
 

MPG

Utente Attivo
544
4
Ciao MPG,


Codice:
boolean palindroma(String s) {
    boolean ris;
    IF (s.length() <= 1)
        ris = true;
    ELSE
        ris = (s.charAt(0) == s.charAt(s.length()-1)) && palindroma(s.substring(1,s.length()-1));
    return ris;
}

Ho allungato molto il brodo, ma essendo il tuo post poco esplicativo (non ho capito se stai approcciando alla ricorsione senza aver studiato un pochino di teoria oppure no) e per evitare di fornirti blocchi di codice da copiare e incollare e inutili al tuo apprendimento, ho tentato di darti una rapida e breve visione per magari fornirti la base su cui ragionare. Il mio consiglio è di partire dagli esercizi più semplici e andare a complicare via via, ma ricordandoti sempre di definire l'algoritmo in termini induttivi.

Ho appena iniziato e devo capire bene il meccanismo...
Scusa non ho capito bene questa parte:

Codice:
ris = (s.charAt(0) == s.charAt(s.length()-1)) && palindroma(s.substring(1,s.length()-1));
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,854
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Ha utilizzato uno pseudo-codice simil Java, e non C++.

Quella parte è praticamente tutto.
La parte prima della AND logica confronta il primo carattere della stringa con l'ultimo; se sono uguali torna true. La seconda parte, dopo la &&, richiama la funzione stessa e quindi torna true, se la condizione citata sopra è vera, o false, in caso contrario.

Se il primo carattere è diverso dall'ultimo, non ha senso valutare nemmeno l'altra parte.
La chiamata ricorsiva alla funzione considera un insieme sempre più piccolo: prende la sottostringa che va dall'indice 1 alla fine.

Comunque esponi i dubbi che hai, soprattutto relativi a quanto devi svolgere (magari mostrandoci dove sei arrivato, e facendo presente i relativi dubbi); in questo modo ti si può rispondere con una maggior precisione.
 

MPG

Utente Attivo
544
4
Nel secondo esercizio ho provato cosi' ma non va..

Codice:
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>

using namespace std;


int somma(int n)
{if (n<=0)
return 0;
else
return n+somma(n-1);
}

int main()
{
int n;
cin>>n;
cout<<somma(n);
}

Nel terzo esercizio so come cercare la palindromia , ma non riesco ad afferrare bene come impostarla con la ricorsione..

Codice:
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>
using namespace std;

bool pal(string s)
{int i=0, l = s.length(); int j = l-1;
while ( (i<=j) )
  {
   if (s[i]!=s[j])
    {return false;}
   else
    {i=i+1; j=j-1;}
  }
return true;
}
int main()
{
    string s;
    cin>>s;
    cout<<pal(s);
}
 
Ultima modifica:

Aramen

Nuovo Utente
4
1
L'algoritmo di risoluzione del secondo esercizio è ok e dovrebbe funzionare. Quindi se puoi spiegarti meglio quando scrivi "cosi' ma non va" per capire se hai un errore a tempo di esecuzione, o un errore logico a monte.

Ora partendo dal secondo esercizio, immediatamente puoi notare che nel terzo esercizio all'interno della funzione pal, non esiste nessuna chiamata ricorsiva e che quindi quella funzione non può essere ricorsiva (la conferma la hai dal fatto che stai utilizzando un while che itera su tutta la stringa.
Ritorniamo a ragionare sui tre casi che ti ho postato ieri e ti riscrivo quì sotto per comodità e cerchiamo di trovarli all'interno della funzione che hai scritto tu:
  1. la stringa vuota è palindroma
  2. la stringa con un solo carattere è palindroma
  3. la stringa x y z è palindroma, se y è una stringa palindroma e x e z sono due caratteri uguali
In particolare la condizione 1 ci suggerisce un caso base del tipo "se la stringa è vuota allora è palindroma -> se s.length == 0 allora return true; la condizione 2 ci suggerisce un'estensione del caso base del tipo "se la stringa ha un solo carattere allora è palindroma -> se s.length <= 1 allora return true; quindi possiamo mettere insieme le due condizioni in un unico caso base con la condizione più restrittiva che è s.length <= 1;
Ora il terzo caso proviamo a riscriverlo in questi termini " una stringa è palindroma, se una sua sottostringa (in particolare quella "interna" privata di primo e ultimo carattere) è palindroma e due suoi elementi rispettano una particolare condizione". Come puoi vedere sto affermando che una stringa è palindroma se una sua parte più piccola è anche essa palindroma il che dovrebbe suggerirti di utilizzare la ricorsione.

Quindi il caso 1 e 2 possiamo riassumerli in questa istruzione condizionale
Codice:
IF (s.length() <= 1)
    ris = true;
Mentre il caso 3 dobbiamo per forza (vista la natura della ricorsione) inserirli nel momento in cui il caso 1 e il caso 2 non si verificano
Codice:
ELSE
    ris = (s[0] == s[s.length()-1] && palindroma(s.substring(1,s.length()-1));
in questo pseudo-codice con s.substring indico una funzione che ti ritorna una sottostringa compresa tra due indici che in questo caso sono il secondo carattere (indice 1) e penultimo carattere (indice s.length()-1), devi trovare il tuo equivalente su C++.
In questa situazione puoi notare come nel caso in cui non verifichiamo i due casi base (stringa vuota o con un solo carattere), andiamo prima a confrontare primo e ultimo carattere e poi chiamiamo la stessa funzione ma su una stringa più piccola. In questo modo hai la ricorsione.

Per allungare ancora di più il brodo ti illustro alcuni casi per farti capire il funzionamento dell'algoritmo con alcuni valori di input della stringa s:

caso 1: s = "c" la stringa c è palindroma perchè quando chiami la funzione pal(s) entriamo nell'IF poichè siamo nel caso 2 (stringa con 1 elemento) e quindi ritorna true.

caso 2: s = "ciao" la stringa c non è palindroma perchè quando chiami la funzione pal(s) non ti trovi nei casi base (1 e 2) e quindi viene eseguito il corpo dell'ELSE. In particolare avrai "c" == "o" e quindi l'AND all'interno dell'ELSE ritornerà false senza dover chiamare la funzione sulla sottostringa "ia".

caso 3: s = "ciac" la stringa c non è palindroma perchè quando chiami la funzione pal(s) non ti trovi nei casi base (1 e 2) e quindi viene eseguito il corpo dell'ELSE. In particolare avrai "c" == "c" e quindi la seconda parte dell'AND viene eseguita e in questo caso verrà chiamata la funzione sulla sottostringa "ia" che ritornerà false in quanto vale il discorso fatto nel caso 2 sopra illustrato.

caso 4: s = "ciic" la stringa è palindroma perchè alla prima esecuzione avrai la situazione illustrata nel caso 3, alla seconda esecuzione avrai la situazione illustrata nel caso 3 in particolare con la sottostringa "ii", e nella terza esecuzione avrai la situazione di stringa vuota che quindi ritorna true.

Spero di essere stato esaustivo e chiaro.
 
  • Mi piace
Reazioni: MPG

MPG

Utente Attivo
544
4
Il problema è che non ho studiato "substring" non cè altro modo?
 
Ultima modifica:

Aramen

Nuovo Utente
4
1
Uno spassionato consiglio, prova a sbatterci un pochino la testa prima di alzare bandiera bianca. Non si tratta di studiare s.substring piuttosto che s.length ma in questi casi come ti ho più volte detto si tratta di tradurre uno pseudo-codice nei tuoi linguaggi. In due post ti ho spiegato il funzionamento di una ipotetica funzione s.substring quindi basta utilizzare un motore di ricerca e vedi che ti escono risultati di questo tipo alla domanda "substring function in c++"

http://www.cplusplus.com/reference/string/string/substr/

Inotre il secondo come l'ho fatto pero' non va...

Nella programmazione questo tipo di affermazione può voler dire tutto. Spiega la natura dell'errore e anche quì non alzare bandiera bianca dopo 6 minuti di orologio dal mio post.
 

MPG

Utente Attivo
544
4
Uno spassionato consiglio, prova a sbatterci un pochino la testa prima di alzare bandiera bianca. Non si tratta di studiare s.substring piuttosto che s.length ma in questi casi come ti ho più volte detto si tratta di tradurre uno pseudo-codice nei tuoi linguaggi. In due post ti ho spiegato il funzionamento di una ipotetica funzione s.substring quindi basta utilizzare un motore di ricerca e vedi che ti escono risultati di questo tipo alla domanda "substring function in c++"

http://www.cplusplus.com/reference/string/string/substr/



Nella programmazione questo tipo di affermazione può voler dire tutto. Spiega la natura dell'errore e anche quì non alzare bandiera bianca dopo 6 minuti di orologio dal mio post.

No scusa il secondo che ho fatto è giusto , per il substring è solo appunto che non l'ho studiato e dovrei cercare di capire come fare in c++... ho visto il link ma non riesco a trovare la soluzione idonea (non è da poco che ci penso anche ti ho risposto subito prima..)
 

Aramen

Nuovo Utente
4
1
Quella che ti ho mandato è la documentazione della funzione substring. La differenza tra la mia versione nello pseudo e questa linkata è nel secondo parametro: in particolare io indicavo il carattere finale della sottostringa, nella versione C++ devi indicare la lunghezza. Non trovo la difficoltà invece di calcolare l'ultimo carattere devi calcolare la lunghezza tale da prendere n-2 caratteri della stringa di partenza
 

MPG

Utente Attivo
544
4
Il primo esercizio l'ho risolto il terzo non ci riesco....

Codice:
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>

using namespace std;


int somma(int n)
{if (n==0)
return 0;
    if (n==1)
return 1;
//se numeri primi pari return 0:
else if (n%2==1)
//dispari
    // se numeri primi pari N%2==0

return n+somma(n-2);
else
   return (n-1)+somma(n-2);
}

int main()
{
int n;
cin>>n;
cout<<somma(n);
}
Post unito automaticamente:

Ho trovato cosi' leggendo tantissimo online pero' non va e vorrei cpaire meglio il passaggio
"return (str[0] == str[len - 1] && Palindrome(str.substr(1, len - 2)));"

Codice:
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>
using namespace std;

bool Palindrome(string str)
{
int len = str.length();
if (len <= 1) {
return true;
}
else
{
return (str[0] == str[len - 1] && Palindrome(str.substr(1, len - 2)));
}
}

int main()
{
    string str;
    cin>>str;
    cout<<Palindrome(str);
}
 
Ultima modifica:

rodhellas

Utente Èlite
1,522
427
CPU
Ryzen 5 3600
Dissipatore
GELID Phantom
Scheda Madre
MSI B450 Gaming Plus Max
HDD
500GB m.2 + 2TB HDD
RAM
16GB Corsair LPX 3000mhz
GPU
Gigabyte GTX 960 OC
Audio
Integrata
Monitor
SyncMaster 223BW
PSU
Antec HCG-520M
Case
Meshify C
Net
Gigabit Fastweb
OS
Windows 10 64bit
Codice:
return (str[0] == str[len - 1] && Palindrome(str.substr(1, len - 2)));
(str[0] == str[len - 1] = il primo char della stringa è uguale all'ultimo (es, anna = vero, ciao = falso)
Palindrome(str.substr(1, len - 2))) = richiami la funzione e gli passi la stessa stringa ma partendo dal secondo carattere fino al penultimo (es. annaanna diventa nnaann, poi naan e infine aa).
Comunque non ti va perchè devi controllare che la lunghezza sia maggiore di 3, se è uguale a 1 ritorni true (come hai già fatto), se è uguale a 2 la lunghezza, return str[0] == str[len - 1] e fine. Se >= 3 rifai tutta la pappardella
 
  • Mi piace
Reazioni: MPG

campo23

Utente Attivo
621
118
CPU
Ryzen 7 3700x
Dissipatore
Noctua NH-U12A
Scheda Madre
MSI X570 Gaming Edge WIFI
HDD
Samsung 960 EVO 256gb
RAM
Vengeance DDR4 32GB 3000Mhz
GPU
EVGA RTX 2060 XC Black
Monitor
Samsung U28H750
PSU
Seasonic Focus Gold 650
Case
Phanteks Eclipse P400 Tempered Glass
OS
Windows 11 Professional x64
Il primo esercizio l'ho risolto il terzo non ci riesco....

Codice:
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>

using namespace std;


int somma(int n)
{if (n==0)
return 0;
    if (n==1)
return 1;
//se numeri primi pari return 0:
else if (n%2==1)
//dispari
    // se numeri primi pari N%2==0

return n+somma(n-2);
else
   return (n-1)+somma(n-2);
}

int main()
{
int n;
cin>>n;
cout<<somma(n);
}
Post unito automaticamente:

Ho trovato cosi' leggendo tantissimo online pero' non va e vorrei cpaire meglio il passaggio
"return (str[0] == str[len - 1] && Palindrome(str.substr(1, len - 2)));"

Codice:
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>
using namespace std;

bool Palindrome(string str)
{
int len = str.length();
if (len <= 1) {
return true;
}
else
{
return (str[0] == str[len - 1] && Palindrome(str.substr(1, len - 2)));
}
}

int main()
{
    string str;
    cin>>str;
    cout<<Palindrome(str);
}

te lo spiego con un esempio così è più facile da capire:
all'inizio hai la stringa iniziale "otto", len quindi è 4
viene chiamato return ("o"=="o" &&Palindrome(str.substr(1,len-2))); che sarà quindi TRUE && risultato della nuova chiamata

la stringa ora è "tt", quindi len è 2. "t"=="t" è vera quindi TRUE, richiamo Palindrome(...) di nuovo

ora hai stringa vuota "", quindi len è 0 e fai direttamente return TRUE. Ora inizi a ritornare indietro: al passaggio precedente hai quindi return TRUE && TRUE, quindi TRUE, stessa cosa per quello ancora prima, quindi il risultato finale sarà TRUE
 
  • Mi piace
Reazioni: MPG

MPG

Utente Attivo
544
4
Somma di elementi di un array , non va
mi da "cannot open output file, name.exe permission denied"
Cosa non va?
(devo usare Codeblocks)


Codice:
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>

using namespace std;


int somma(int A[], int n)
{if (n=0)
return 0;
else
return A[n] + somma (A, n-1);
}

int main()
{
int n;
cin>>n;
int A[n];
cin>>A[n];
cout<<somma(A, n);
}
 

Ci sono discussioni simili a riguardo, dai un'occhiata!

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili