|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
[C] verificare se un albero binario è un abr
Ciao a tutti ho il seguente problema: devo verificare se un albero binario è un albero binario di ricerca. Spero che mi aiutate grazie
Codice:
void verifica(nod *radice, int abr)/*ritorna zero se e un abr 1 se non è*/ { if (radice!=NULL) { printf("radice uguale a %d \n",radice->info); if (((radice->sinistro==NULL)&&(radice->destro->info<radice->info))|| ((radice->destro==NULL)&&(radice->sinistro->info>radice->info))|| ((radice->destro->info<radice->info)&&(radice->sinistro->info<radice->info))) { abr=1; } else { verifica(radice->sinistro,0); verifica(radice->destro,0); } } } |
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2774
|
Faccio due considerazioni che dovrebbero condurti sulla buona strada:
- questa funzione deve restituire un valore, quindi perché è void? - se sia il ramo sx che il dx sono NULL cosa succede? |
![]() |
![]() |
![]() |
#3 |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
ciao avevo pensato di usare una vodi visto che devo ricordarmi il valore di abr precedente. Poi per quanto riguarda se entrambi i figli sono uguali a null deve fermarsi e questo che non riesco a fare. Se saresti piu esplicito forse capisco meglio. grazie
|
![]() |
![]() |
![]() |
#4 | |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 1945
|
Quote:
per quanto riguarda il fatto se un nodo non ha figlio destro e sinistro il risultato è true (cioè 1).... io farei una cosa del tipo.... (molto al volo) Codice:
se nodo == null return 1; se nodo.left == null && nodo.right == null return 1; qui effettui i controlli su entrambi i figli se uno solo dei due non soddisfa la condizione puoi ritornare direttamente 0 ora qui fai una chiamata ricorsiva su entrambi i figli della funzione ricorda che deve essere vero per entrambi Codice:
int isBst(nod * radice) //o comunque chiamala come vuoi |
|
![]() |
![]() |
![]() |
#5 |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
ho fatto come mi dicevi.
Codice:
int verifica(nod *radice)/*ritorna zero se e un abr 1 se non è*/ { if ((radice==NULL)||((radice->sinistro==NULL)&&(radice->destro==NULL))) { return 0; } else if (((radice->sinistro==NULL)&&(radice->destro->info<radice->info))|| ((radice->destro==NULL)&&(radice->sinistro->info>radice->info))|| ((radice->destro->info<radice->info)&&(radice->sinistro->info<radice->info))) { return 1; } else { ; return (verifica(radice->sinistro)); return (verifica(radice->destro)); } } 1 mi restituisce sempre 0, se non metto return 0 mi restituisce sempre 1. 2 non richiamo il figlio destro SPero mi aiuti perche non so piu cha fare. ![]() |
![]() |
![]() |
![]() |
#6 | |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 1945
|
Quote:
![]() due return non si possono proprio vedere..... semplifica la cosa levando un po di roba che almeno ti semplifica la vita... intanto il passo base della ricorsione è fatto bene se non fosse che devi ritornare 1. Si perchè un albero binario è banalmente binario se non ha figli (cioè è una foglia) e il controllo se il nodo stesso è null diciamo che neanche servirebbe in questo caso ma ce lo mettiamo lo stesso quindi Codice:
se nodo == null || (nodo.left == null && nodo.right == null)return 1; controlli i figli Codice:
se (nodo.left != null) && (nodo.left.info > nodo.info)return 0 se (nodo.right != null) && (nodo.right.info <= nodo.info) return 0 adesso però devi vedere che tutti gli altri nodi non ritornino 0 Codice:
return isBst(nodo.left) && isBst(nodo.right) spero di non aver sbagliato nulla edit gli else non servono a nulla in questo caso, omettili adesso almeno rendono un po più leggibile il codice |
|
![]() |
![]() |
![]() |
#7 | |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
Quote:
|
|
![]() |
![]() |
![]() |
#8 |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 1945
|
Non ci avevo fatto caso che doveva essere il contrario...vabbè comunque basta davvero poco per modificarlo...
|
![]() |
![]() |
![]() |
#9 |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
scusa ma il caso base e che il nodo non ha figli o e lui stesso NULL e restituisce 0 come avevo fatto......
![]() |
![]() |
![]() |
![]() |
#10 |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 1945
|
Guarda stai impazzendo per nulla... se hai capito quello che ti ho scritto prima ti basta modificare poche cose...più di questo dovrei darti la soluzione...e non mi pare il caso
comunque posta il tuo codice. |
![]() |
![]() |
![]() |
#11 |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
continua a non funzionarmi come in questo caso:
5 \ 7 / 3 va in loop. 5 radice 7 figlio destro di 5 e 3 figlio sinistro di 7. Codice:
int verifica(nod *radice)/*ritorna zero se e un abr 1 se non è*/ { if ((radice==NULL)||((radice->sinistro==NULL)&&(radice->destro==NULL))) { printf("fine \n"); return 0; } else if (((radice->sinistro==NULL)&&(radice->destro->info<radice->info))|| ((radice->destro==NULL)&&(radice->sinistro->info>radice->info))|| ((radice->destro->info<radice->info)&&(radice->sinistro->info<radice->info))) { printf("l albero non e' un abr \n"); return 1; } else { printf("andiamo avanti con la funzione \n"); return (verifica(radice->sinistro)||verifica(radice->destro)); } } |
![]() |
![]() |
![]() |
#12 |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Prova a semplificarlo ancora un po:
- caso base: Se il nodo e' NULL allora ritorna 1 (si, e' un albero di ricerca); - caso base: se uno dei due nodi, sinistro/destro e' NULL, allora ritorna 1 in accordo all'ordine che hai scelto (cioe', se sx!=NULL, allora confronta sx con root e se sx < root ritorni 1); - caso base :Se sia sx sia dx sono != NULL (quindi hai fatto i controlli di cui sopra) allora puoi confrontare sx->root->dx. Se non rispettano l'ordine, ritorni 0. Siccome hai trovato un caso, tutto l'albero non e' di ricerca e le tue ricorsioni verranno interrotte perche' sai gia' il risultato. Infine (caso ricorsivo) ti rimane che sx e dx sono != NULL e sono nell'ordine giusto. Allora puoi fare l'AND fra le chiamate ricorsive a sx e dx e ritornare il risultato. Fai le prove partendo da alberi semplici (i.e. verifica i casi base prima di tutto) Spero ti sia d'aiuto
__________________
In God we trust; all others bring data |
![]() |
![]() |
![]() |
#13 | |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 1945
|
Quote:
![]() mettendo tutta quella roba in un'unica espressione rischi di fare degli errori e non riuscire a capire dove quella parte in rosso cancellala totalmente... sostituisci con qualcosa del tipo Codice:
se nodo.left != null && nodo.left.value > nodo.value return 1 se nodo.right != null && nodo.right.value <= nodo.value return 1 Cancella anche tutti gli else che ci sono. Non sono un errore usarli, ma non servono ora e levandoli migliori la lettura del codice Comunque fattelo dire ritornare 0 (false) se è un albero binario e 1 (true) se non lo è è una cosa molto anomala... ![]() |
|
![]() |
![]() |
![]() |
#14 | |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
Quote:
anke in caso di albero semplice : 5 3 6 Codice:
int verifica(nod *radice)/*ritorna zero se e un abr 1 se non è*/ { if ((radice==NULL)||((radice->sinistro==NULL)&&(radice->destro==NULL))) { printf("fine \n"); return 0; } else { printf("valore del nodo analizzato uguale a %d \n",radice->info); if ((radice->sinistro!=NULL)&&(radice->sinistro->info>radice->info)) return 1; if ((radice->destro!=NULL)&&(radice->destro->info>radice->info)) return 1; return (verifica(radice->sinistro)&&verifica(radice->destro)); } } |
|
![]() |
![]() |
![]() |
#15 |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 1945
|
C'è un errore nel return finale che prima non avevi fatto
|
![]() |
![]() |
![]() |
#16 |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
|
![]() |
![]() |
![]() |
#17 |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 1945
|
|
![]() |
![]() |
![]() |
#18 |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
ho fatto come dicevi
Codice:
int verifica(nod *radice)/*ritorna zero se e un abr 1 se non è*/ { if ((radice==NULL)||((radice->sinistro==NULL)&&(radice->destro==NULL))) { return 0; } else { if ((radice->sinistro!=NULL)&&(radice->sinistro->info>radice->info)) return 1; if ((radice->destro!=NULL)&&(radice->destro->info<radice->info)) return 1; else return (verifica(radice->sinistro)||verifica(radice->destro)); } } se io ho un albero in cui i figli rispettano la proprieta verso il padre ma non verso il nonno diciamo cosi quest algoritmo non va bene. ESEMPIO 5 \ 7 / 2 in questo caso mi restituisce che e un ABR perche controlla che 2 è minore di 7 e che 7 è maggiore di 5. ma non che 2 stando a destra di 5 dovrebbe essere maggiore di 5. non so se ho reso l idea |
![]() |
![]() |
![]() |
#19 |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 1945
|
Effettivamente hai ragione.. non avevamo considerato questa cosa! Potresti provare allora con una visita in-order e verificare che ogni nodo sia minore del successivo... Questa cosa mi era proprio sfuggita
![]() |
![]() |
![]() |
![]() |
#20 |
Member
Iscritto dal: Nov 2010
Messaggi: 71
|
hai ragione proverò a farlo
|
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 05:53.