Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Sony INZONE H6 Air: il primo headset open-back di Sony per giocatori
Sony INZONE H6 Air: il primo headset open-back di Sony per giocatori
Il primo headset open-back della linea INZONE arriva a 200 euro con driver derivati dalle cuffie da studio MDR-MV1 e un peso record di soli 199 grammi
Nutanix cambia pelle: dall’iperconvergenza alla piattaforma full stack per cloud ibrido e IA
Nutanix cambia pelle: dall’iperconvergenza alla piattaforma full stack per cloud ibrido e IA
Al .NEXT 2026 di Chicago, Nutanix ha mostrato quanto sia cambiata: una piattaforma software che gestisce VM, container e carichi di lavoro IA ovunque, dall’on-premise al cloud pubblico. Con un’esecuzione rapidissima sulle partnership e sulla migrazione da VMware
Recensione Xiaomi Pad 8 Pro: potenza bruta e HyperOS 3 per sfidare la fascia alta
Recensione Xiaomi Pad 8 Pro: potenza bruta e HyperOS 3 per sfidare la fascia alta
Xiaomi Pad 8 Pro adotta il potente Snapdragon 8 Elite all'interno di un corpo con spessore di soli 5,75 mm e pannello LCD a 144Hz flicker-free, per un tablet che può essere utilizzato con accessori dedicati di altissima qualità. Fra le caratteristiche esclusive, soprattutto per chi intende usarlo con la tastiera ufficiale, c'è la modalità Workstation di HyperOS 3, che trasforma Android in un sistema operativo con interfaccia a finestre
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 24-08-2012, 08:56   #1
Gabry610
Junior Member
 
Iscritto dal: Jun 2010
Messaggi: 9
[C] - Esercizio albero di ricerca binaria

Buongiorno a tutti!
Sto studiando per l'esame di programmazione di settembre e sono incappato in un esercizio che non mi convince del tutto.
Mi sto preparando sul noto libro di Deitel & Deitel - "C Corso completo di programmazione". Il materiale che vi allego è completamente opensource e scaricabile dal sito dell'editore.

L'esercizio in questione è il "Fig12.19" del capitolo "Le strutture dati in C", per coloro che avessero a disposizione il testo.
In sostanza, il programma mostra l'inserimento di dati all'interno di un albero binario. Il codice è il seguente:

Codice:
/* Fig. 12.19: fig12_19.c
   Create a binary tree and traverse it 
   preorder, inorder, and postorder */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* self-referential structure */
struct treeNode { 
   struct treeNode *leftPtr; /* pointer to left subtree */
   int data; /* node value */
   struct treeNode *rightPtr; /* pointer to right subtree */
}; /* end structure treeNode */

typedef struct treeNode TreeNode; /* synonym for struct treeNode */
typedef TreeNode *TreeNodePtr; /* synonym for TreeNode* */

/* prototypes */
void insertNode( TreeNodePtr *treePtr, int value );
void inOrder( TreeNodePtr treePtr );
void preOrder( TreeNodePtr treePtr );
void postOrder( TreeNodePtr treePtr );

/* function main begins program execution */
int main( void )
{ 
   int i; /* counter to loop from 1-10 */
   int item; /* variable to hold random values */
   TreeNodePtr rootPtr = NULL; /* tree initially empty */

   srand( time( NULL ) ); 
   printf( "The numbers being placed in the tree are:\n" );

   /* insert random values between 0 and 14 in the tree */
   for ( i = 1; i <= 10; i++ ) { 
      item = rand() % 15;
      printf( "%3d", item );
      insertNode( &rootPtr, item );
   } /* end for */

   /* traverse the tree preOrder */
   printf( "\n\nThe preOrder traversal is:\n" );
   preOrder( rootPtr );

   /* traverse the tree inOrder */
   printf( "\n\nThe inOrder traversal is:\n" );
   inOrder( rootPtr );

   /* traverse the tree postOrder */
   printf( "\n\nThe postOrder traversal is:\n" );
   postOrder( rootPtr );
   return 0; /* indicates successful termination */
} /* end main */

/* insert node into tree */
void insertNode( TreeNodePtr *treePtr, int value )
{ 
   /* if tree is empty */
   if ( *treePtr == NULL ) {   
      *treePtr = malloc( sizeof( TreeNode ) );

      /* if memory was allocated then assign data */
      if ( *treePtr != NULL ) { 
         ( *treePtr )->data = value;
         ( *treePtr )->leftPtr = NULL;
         ( *treePtr )->rightPtr = NULL;
      } /* end if */
      else {
         printf( "%d not inserted. No memory available.\n", value );
      } /* end else */
   } /* end if */
   else { /* tree is not empty */
      /* data to insert is less than data in current node */
      if ( value < ( *treePtr )->data ) {
         insertNode( &( ( *treePtr )->leftPtr ), value );
      } /* end if */

      /* data to insert is greater than data in current node */
      else if ( value > ( *treePtr )->data ) {
         insertNode( &( ( *treePtr )->rightPtr ), value );
      } /* end else if */
      else { /* duplicate data value ignored */
         printf( "dup" );
      } /* end else */
   } /* end else */
} /* end function insertNode */

/* begin inorder traversal of tree */
void inOrder( TreeNodePtr treePtr )
{ 
   /* if tree is not empty then traverse */
   if ( treePtr != NULL ) { 
      inOrder( treePtr->leftPtr );
      printf( "%3d", treePtr->data );
      inOrder( treePtr->rightPtr );
   } /* end if */
} /* end function inOrder */

/* begin preorder traversal of tree */
void preOrder( TreeNodePtr treePtr )
{ 
   /* if tree is not empty then traverse */
   if ( treePtr != NULL ) { 
      printf( "%3d", treePtr->data );
      preOrder( treePtr->leftPtr );
      preOrder( treePtr->rightPtr );
   } /* end if */
} /* end function preOrder */

/* begin postorder traversal of tree */
void postOrder( TreeNodePtr treePtr )
{ 
   /* if tree is not empty then traverse */
   if ( treePtr != NULL ) { 
      postOrder( treePtr->leftPtr );
      postOrder( treePtr->rightPtr );
      printf( "%3d", treePtr->data );
   } /* end if */
} /* end function postOrder */



/**************************************************************************
 * (C) Copyright 1992-2010 by Deitel & Associates, Inc. and               *
 * Pearson Education, Inc. All Rights Reserved.                           *
 *                                                                        *
 * DISCLAIMER: The authors and publisher of this book have used their     *
 * best efforts in preparing the book. These efforts include the          *
 * development, research, and testing of the theories and programs        *
 * to determine their effectiveness. The authors and publisher make       *
 * no warranty of any kind, expressed or implied, with regard to these    *
 * programs or to the documentation contained in these books. The authors *
 * and publisher shall not be liable in any event for incidental or       *
 * consequential damages in connection with, or arising out of, the       *
 * furnishing, performance, or use of these programs.                     *
 *************************************************************************/
La mia attenzione va soprattutto all'utilizzo della funzione insertNode. L'inizio mi è chiaro, cioè ho capito che se l'albero è vuoto, il nuovo dato farà parte di un nodo che verrà inserito come nodo "iniziale" dell'albero (nodo padre esclusivo). Il problema che ho io è nel comprendere appieno la parte seguente, ovvero:

Codice:
if ( value < ( *treePtr )->data ) {
         insertNode( &( ( *treePtr )->leftPtr ), value );
      } /* end if */

      /* data to insert is greater than data in current node */
      else if ( value > ( *treePtr )->data ) {
         insertNode( &( ( *treePtr )->rightPtr ), value );
      } /* end else if */
Se il valore passato a insertNode è minore o maggiore del nodo corrente, la funzione verrà richiamata in modo ricorsivo passando rispettivamente l'indirizzo del sottoalbero sinistro o destro.
E' chiaro, ma secondo me non è del tutto esatto!
Mi spiego: così facendo, viene ignorato ad ogni ciclo un ramo di (sotto)albero.
Se un certo valore è minore del nodo, verrà considerato il suo sottonodo sinistro (il sottonodo DESTRO non verrà più riconsiderato e rimarrà senza sottonodi). Il sottonodo destro è destinato a rimanere così, perchè mi sembra che il passaggio iterativo continui a partire dal sottonodo sinistro: ancora se si considera un altro valore (maggiore o minore) di questo sottonodo sinistro, verrà rievocata la funzione insertNode con l'indirizzo del suo sottonodo (destro o sinistro). In altre parole, scelto un nodo si considereranno sempre i suoi sottonodi e così via, perdendo il legame col nodo "fratello".

Secondo voi è corretta come interpretazione?
Mi scuso, mi rendo pienamente conto che a parole possa risultare estremamente contorto; vi chiedo se per favore potete fare questo sforzo per aiutarmi a dileguare i miei dubbi!
Gabry610 è offline   Rispondi citando il messaggio o parte di esso
Old 24-08-2012, 12:39   #2
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2789
Quote:
Mi spiego: così facendo, viene ignorato ad ogni ciclo un ramo di (sotto)albero.
Se un certo valore è minore del nodo, verrà considerato il suo sottonodo sinistro (il sottonodo DESTRO non verrà più riconsiderato e rimarrà senza sottonodi).
Il ramo destro rimarrà senza nodi fintantoché non verrà inserito un valore > della radice.
Inserendo i nodi in questo modo con una visita in preordine ottieni i numeri ordinati.
Ma forse questo non risponde ai tuoi dubbi?
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 24-08-2012, 13:51   #3
demos88
Senior Member
 
Iscritto dal: Nov 2004
Città: Padova
Messaggi: 2342
Quote:
Originariamente inviato da Gabry610 Guarda i messaggi
Mi spiego: così facendo, viene ignorato ad ogni ciclo un ramo di (sotto)albero.
Se un certo valore è minore del nodo, verrà considerato il suo sottonodo sinistro (il sottonodo DESTRO non verrà più riconsiderato e rimarrà senza sottonodi). Il sottonodo destro è destinato a rimanere così, perchè mi sembra che il passaggio iterativo continui a partire dal sottonodo sinistro: ancora se si considera un altro valore (maggiore o minore) di questo sottonodo sinistro, verrà rievocata la funzione insertNode con l'indirizzo del suo sottonodo (destro o sinistro). In altre parole, scelto un nodo si considereranno sempre i suoi sottonodi e così via, perdendo il legame col nodo "fratello".
A me sembra corretto... non capisco il tuo dubbio sul sottonodo sinistro.
Partendo dalla radice, l'insert va a cercare la posizione nell'albero dove inserire il nodo. Se il valore da inserire è minore del nodo corrente, scende nel sottoalbero sinistro, altrimenti destro (se è uguale viene ignorato e finisce) ricorsivamente fino a che non trova un nodo NULL, ovvero un figlio sinistro o destro che ancora non esiste, e lo crea.
Non capisco quale sia il problema di "ignorare" un sottoalbero ad ogni ciclo, un valore può essere o maggiore o minore o uguale a un altro, non può essere sia minore che maggiore. Se è minore, lascio perdere il sottoalbero destro e viceversa per ogni nodo. Il fatto di ignorare ad ogni passaggio una parte dell'albero è il motivo principale per cui si usano gli alberi, ovvero poter ottenere l'estrazione o l'inserimento ordinato di valori mediante una operazione di complessità O(log(n)).
Nel caso peggiore, che forse è quello che ti sta creando confusione, ho un albero i cui nodi hanno solo figli sinistri o solo figli destri, ma tale situazione è possibile solo se inserisco un set di valori ordinatamente crescenti o descrescenti. In questo caso il BST (albero di ricerca binario) diventa meno efficiente e gli inserimenti comportano una complessità O(n).
Questa problematica è mitigata dagli alberi AVL che integrano un meccanismo di bilanciamento dell'albero.


ps: Hai provato il codice?
__________________
CPU Ryzen 2600 @ 3,95Ghz + Bequiet Dark Rock TF / MB Asus X470-F Gaming / RAM 2x8GB DDR4 G.Skill FlareX 3200 CL14 / VGA Sapphire RX 7900 XT Nitro+ @ 3200Mhz / SSD Samsung 970 Pro 512GB + Sandisk 240GB Plus + Sandisk 960GB Ultra II PSU Seasonic Platinum P-660 / Headset Kingston HyperX Flight
demos88 è offline   Rispondi citando il messaggio o parte di esso
Old 24-08-2012, 14:01   #4
Gabry610
Junior Member
 
Iscritto dal: Jun 2010
Messaggi: 9
A me non sembra. Supponiamo ad esempio di avere un albero con un solo nodo che contiene il valore 10.
Viene passato alla funzione il valore 9. A questo punto la funzione richiamerà se stessa in questo modo:

Codice:
 insertNode( &( ( *treePtr )->leftPtr ), value );
Supponiamo adesso che venga passato il valore 11.
La funzione richiamerà se stessa in questo modo:

Codice:
 insertNode( &( ( *treePtr )->rightPtr ), value );
Ma a questo punto:

Codice:
( *treePtr )->rightPtr
indicherà il nodo DESTRO di quello che prima era il SINISTRO di quello iniziale secondo me.

Schematizzerei in questo modo:



P.S. Scusami demos, ho fatto crossposting con te quindi ho letto la tua risposta dopo questo messaggio!
Gabry610 è offline   Rispondi citando il messaggio o parte di esso
Old 24-08-2012, 14:09   #5
demos88
Senior Member
 
Iscritto dal: Nov 2004
Città: Padova
Messaggi: 2342
Ah ho capito il tuo dubbio, ma l'albero fa proprio quello che tu ti aspetti sia giusto, solo che forse ti perdi sulla ricorsione e sulla visibilità di quei puntatori. Infatti ogni inserimento non parte dall'ultimo nodo inserito o dal suo padre, ma parte sempre dalla radice.
Ne hai un esempio proprio nel codice che hai postato:
Codice:
 /* insert random values between 0 and 14 in the tree */
   for ( i = 1; i <= 10; i++ ) { 
      item = rand() % 15;
      printf( "%3d", item );
      insertNode( &rootPtr, item );
   } /* end for */
per ogni valore random, viene effettuato un inserimento richiamando insertNode sulla radice dell'albero. Proprio come deve essere
__________________
CPU Ryzen 2600 @ 3,95Ghz + Bequiet Dark Rock TF / MB Asus X470-F Gaming / RAM 2x8GB DDR4 G.Skill FlareX 3200 CL14 / VGA Sapphire RX 7900 XT Nitro+ @ 3200Mhz / SSD Samsung 970 Pro 512GB + Sandisk 240GB Plus + Sandisk 960GB Ultra II PSU Seasonic Platinum P-660 / Headset Kingston HyperX Flight
demos88 è offline   Rispondi citando il messaggio o parte di esso
Old 24-08-2012, 14:49   #6
Gabry610
Junior Member
 
Iscritto dal: Jun 2010
Messaggi: 9
Hai ragione. Riparte sempre dall'inizio dell'albero a fare il controllo

Ti ringrazio demos
Gabry610 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Sony INZONE H6 Air: il primo headset open-back di Sony per giocatori Sony INZONE H6 Air: il primo headset open-back d...
Nutanix cambia pelle: dall’iperconvergenza alla piattaforma full stack per cloud ibrido e IA Nutanix cambia pelle: dall’iperconvergenza alla ...
Recensione Xiaomi Pad 8 Pro: potenza bruta e HyperOS 3 per sfidare la fascia alta Recensione Xiaomi Pad 8 Pro: potenza bruta e Hyp...
NZXT H9 Flow RGB+, Kraken Elite 420 e F140X: abbiamo provato il tris d'assi di NZXT NZXT H9 Flow RGB+, Kraken Elite 420 e F140X: abb...
ASUS ROG Swift OLED PG34WCDN recensione: il primo QD-OLED RGB da 360 Hz ASUS ROG Swift OLED PG34WCDN recensione: il prim...
Addio definitivo a iOS 26.4, Apple blocc...
EPYC di nuova generazione: AMD supporter...
AMD, Arm e Qualcomm scommettono su Wayve...
Intel potrebbe estendere la vita del soc...
Windows, gli aggiornamenti di aprile for...
Addio cavi perimetrali: il robot tosaerb...
Google Pixel 10 oggi proposto a soli 549...
I robot di Boston Dynamics possono inter...
Tech, gadget e accessori a meno di 5€ su...
Ford riorganizza la divisione elettrica:...
Elon Musk trasforma xAI in fornitore di ...
Pirateria musicale: batosta record per A...
iRobot riparte: nuova era con Picea, Roo...
Bitcoin: Killing Satoshi, film sul miste...
Haier Mini LED 4K da 65 pollici a soli 5...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 12:30.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v