Alberi binari in C: una guida completa per principianti

Ultimo aggiornamento: 14 gennaio 2026
  • Struttura gerarchica con nodi che hanno un massimo di due figli; include radice, foglie e livelli.
  • Vantaggi: ricerche e inserimenti efficienti, rappresentazioni gerarchiche e flessibilità dinamica rispetto agli array.
  • Operazioni chiave: attraversamenti (in, pre, post), ricerca, inserimento ed eliminazione per ordinare e gestire i dati.
Alberi binari in C

Benvenuti a questa guida completa sugli alberi binari in C. In questo articolo esploreremo le basi degli alberi binari e come implementarli nel linguaggio di programmazione C. Se sei un principiante nella programmazione o vuoi semplicemente migliorare le tue competenze in C, questa guida è per te.

Gli alberi binari sono strutture dati fondamentali nell'informatica e vengono utilizzati in una vasta gamma di applicazioni. Comprendere come funzionano e come implementarli vi aiuterà a risolvere problemi complessi in modo più efficiente ed elegante.

In questo articolo esploreremo i fondamenti degli alberi binari, tra cui la loro struttura, l'inserimento e la cancellazione di nodi, l'attraversamento e la ricerca di elementi. Forniremo anche esempi pratici nel linguaggio di programmazione C, in modo che possiate vedere come questi concetti vengono applicati nella pratica.

Quindi iniziamo!

Cosa sono gli alberi binari?

Gli alberi binari sono strutture dati gerarchiche composte da nodi interconnessi. Ogni nodo può avere fino a due nodi figlio: uno a sinistra e uno a destra. Questa struttura a due rami è ciò che distingue gli alberi binari dalle altre strutture dati.

In un albero binario, il primo nodo è chiamato nodo radice. I nodi figlio sono chiamati nodi figlio, mentre i nodi senza figli sono chiamati nodi foglia. I nodi allo stesso livello sono chiamati nodi fratelli.

Vantaggi degli alberi binari

Gli alberi binari offrono numerosi vantaggi in termini di efficiente archiviazione e ricerca dei dati. Ecco alcuni dei principali vantaggi:

  1. ricerca efficienteGli alberi binari consentono di ricercare gli elementi in fase di esecuzione più velocemente rispetto ad altre strutture dati, come le liste concatenate. Ciò è dovuto alla struttura gerarchica dell'albero e alla sua capacità di partizionare rapidamente il set di dati.
  2. Inserimento e rimozione flessibiliGli alberi binari sono altamente adattabili alle operazioni di inserimento ed eliminazione dei nodi. A differenza delle strutture dati statiche come gli array, gli alberi binari possono crescere e modificare la loro struttura in modo dinamico.
  3. Rappresentazione delle relazioni gerarchicheGli alberi binari sono particolarmente utili per rappresentare relazioni gerarchiche tra elementi. Ad esempio, in una struttura di directory di file, ogni directory può essere rappresentata come un nodo nell'albero, con sottodirectory e file come nodi figlio.

Struttura di un albero binario

Prima di approfondire l'implementazione degli alberi binari in C, è importante comprenderne la struttura di base. Ogni nodo in un albero binario contiene un valore e riferimenti ai suoi nodi figlio sinistro e destro, se presenti.

La tabella seguente mostra la struttura di un nodo in un albero binario:

Nodo binario
valore
Nodo sinistro
Nodo destro

Ogni nodo può memorizzare qualsiasi tipo di dato, come numeri interi, caratteri o strutture più complesse. Il nodo radice è il punto di partenza dell'albero e da esso possiamo accedere a tutti gli altri nodi.

Implementazione di alberi binari in C

Ora che abbiamo una comprensione di base degli alberi binari, è il momento di implementarli nel linguaggio di programmazione C. Successivamente, vedremo come dichiarare e utilizzare una struttura ad albero binario in C.

Dichiarazione della struttura ad albero binario

In C possiamo dichiarare la struttura di un albero binario utilizzando una struttura e dei puntatori. Ecco la dichiarazione di base della struttura:

struct NodoArbol {
    int valor;
    struct NodoArbol* izquierdo;
    struct NodoArbol* derecho;
};

In questa struttura, valor rappresenta il valore memorizzato nel nodo e izquierdo y derecho sono puntatori rispettivamente ai nodi figlio sinistro e destro.

  Living Intelligence: cos'è, come funziona e perché è importante

Creazione di un nuovo nodo

Per creare un nuovo nodo nell'albero binario, dobbiamo allocare memoria per il nodo e impostarne i valori. Ecco una funzione C che crea un nuovo nodo:

struct NodoArbol* crearNodo(int valor) {
    struct NodoArbol* nodo = (struct NodoArbol*)malloc(sizeof(struct NodoArbol));
    nodo->valor = valor;
    nodo->izquierdo = NULL;
    nodo->derecho = NULL;
    return nodo;
}

La funzione malloc Viene utilizzato per allocare memoria dinamica al nodo. Impostiamo quindi i valori del nodo e restituiamo il nodo creato.

Inserimento di nodi

L'inserimento dei nodi è un processo fondamentale negli alberi binari. Consente di aggiungere nuovi elementi all'albero nella posizione corretta in base al valore del nodo. Di seguito è riportata una funzione C per inserire un nodo in un albero binario:

struct NodoArbol* insertarNodo(struct NodoArbol* raiz, int valor) {
    if (raiz == NULL) {
        return crearNodo(valor);
    }

    if (valor < raiz->valor) {
        raiz->izquierdo = insertarNodo(raiz->izquierdo, valor);
    } else if (valor > raiz->valor) {
        raiz->derecho = insertarNodo(raiz->derecho, valor);
    }

    return raiz;
}

Questa funzione riceve un puntatore alla radice dell'albero e il valore del nodo da inserire. Se root è null, significa che l'albero è vuoto e creiamo un nuovo nodo alla radice. Altrimenti, confrontiamo il valore del nodo con il valore della radice e decidiamo se inserire il nodo a sinistra o a destra.

Eliminazione dei nodi

L'eliminazione dei nodi in un albero binario può essere un po' più complessa. Dipende da diversi casi, ad esempio se il nodo da eliminare ha o meno elementi figlio. Di seguito è riportata una funzione C per eliminare un nodo in un albero binario:

struct NodoArbol* eliminarNodo(struct NodoArbol* raiz, int valor) {
    if (raiz == NULL) {
        return raiz;
    }

    if (valor < raiz->valor) {
        raiz->izquierdo = eliminarNodo(raiz->izquierdo, valor);
    } else if (valor > raiz->valor) {
        raiz->derecho = eliminarNodo(raiz->derecho, valor);
    } else {
        if (raiz->izquierdo == NULL) {
            struct NodoArbol* temp = raiz->derecho;
            free(raiz);
            return temp;
        } else if (raiz->derecho == NULL) {
            struct NodoArbol* temp = raiz->izquierdo;
            free(raiz);
            return temp;
        }

        struct NodoArbol* sucesor = encontrarSucesor(raiz->derecho);
        raiz->valor = sucesor->valor;
        raiz->derecho = eliminarNodo(raiz->derecho, sucesor->valor);
    }

    return raiz;
}

In questa funzione controlliamo se il valore del nodo è minore, maggiore o uguale al valore della radice corrente. A seconda dei casi, eseguiamo le seguenti azioni:

  • Se il valore è inferiore, andiamo a sinistra dell'albero.
  • Se il valore è maggiore, andiamo a destra dell'albero.
  • Se il valore è uguale, troviamo il successore più vicino del nodo (il nodo più piccolo nel sottoalbero destro) e lo sostituiamo con il nodo corrente. Quindi rimuoviamo il successore dal sottoalbero destro.

Attraversamenti negli alberi binari

Le traversate sono operazioni che consentono di visitare tutti i nodi di un albero binario in un certo ordine. Esistono tre tipi comuni di tour:

Attraversamento in ordine : visita prima il sottoalbero sinistro, poi il nodo corrente e infine il sottoalbero destro. Ecco una funzione C che esegue un attraversamento in ordine di un albero binario:

void inOrden(struct NodoArbol* raiz) {
    if (raiz != NULL) {
        inOrden(raiz->izquierdo);
        printf("%d ", raiz->valor);
        inOrden(raiz->derecho);
    }
}

Attraversamento in preordine : visita prima il nodo corrente, poi il sottoalbero sinistro e infine il sottoalbero destro. Ecco una funzione C che esegue un attraversamento in preordine di un albero binario:

void preOrden(struct NodoArbol* raiz) {
    if (raiz != NULL) {
        printf("%d ", raiz->valor);
        preOrden(raiz->izquierdo);
        preOrden(raiz->derecho);
    }
}

Attraversamento in post-ordine : visita prima il sottoalbero sinistro, poi quello destro e infine il nodo corrente. Ecco una funzione C che esegue un attraversamento in post-ordine di un albero binario:

void postOrden(struct NodoArbol* raiz) {
    if (raiz != NULL) {
        postOrden(raiz->izquierdo);
        postOrden(raiz->derecho);
        printf("%d ", raiz->valor);
    }
}

Cerca elementi

La ricerca di elementi in un albero binario consente di trovare rapidamente un valore specifico all'interno della struttura dati. Ecco una funzione C per cercare un elemento in un albero binario:

struct NodoArbol* buscarElemento(struct NodoArbol* raiz, int valor) {
    if (raiz == NULL || raiz->valor == valor) {
        return raiz;
    }

    if (valor < raiz->valor) {
        return buscarElemento(raiz->izquierdo, valor);
    } else {
        return buscarElemento(raiz->derecho, valor);
    }
}

Questa funzione esegue una ricerca ricorsiva nell'albero binario. Se il valore del nodo corrente è uguale al valore cercato, il nodo viene restituito. Altrimenti, la ricerca avviene nel sottoalbero sinistro o destro in base al valore e il processo viene ripetuto finché non viene trovato il valore o non viene raggiunto un nodo nullo.

  Algoritmi brute-force nella programmazione: cosa sono, esempi e differenze con il backtracking.

Esempi di implementazione di alberi binari in C

Ora che abbiamo trattato le basi degli alberi binari e come implementarli in C, diamo un'occhiata ad alcuni esempi pratici.

Esempio 1: Creazione di un albero binario

Supponiamo di voler creare un albero binario con i seguenti valori: 10, 5, 15, 3, 7, 13, 18. Ecco come possiamo farlo in C:

int main() {
    struct NodoArbol* raiz = NULL;

    raiz = insertarNodo(raiz, 10);
    raiz = insertarNodo(raiz, 5);
    raiz = insertarNodo(raiz, 15);
    raiz = insertarNodo(raiz, 3);
    raiz = insertarNodo(raiz, 7);
    raiz = insertarNodo(raiz, 13);
    raiz = insertarNodo(raiz, 18);

    return 0;
}

In questo esempio, creiamo un puntatore alla radice dell'albero e quindi utilizziamo la funzione insertarNodo per aggiungere i valori all'albero.

Esempio 2: Attraversamento in ordine dell'albero binario

Per stampare in ordine i valori dell'albero binario, possiamo chiamare la funzione inOrden nel seguente modo:

int main() {
    // Crear el árbol binario

    printf("Recorrido en orden: ");
    inOrden(raiz);
    printf("\n");

    return 0;
}

Questo esempio stamperà i valori nell'albero in ordine crescente.

Domande frequenti

1. Qual è la differenza tra un albero binario e un albero binario di ricerca?

Un albero binario di ricerca (BST) è un tipo speciale di albero binario in cui gli elementi sono disposti in modo che i valori più piccoli siano a sinistra e quelli più grandi a destra. Ciò consente una ricerca degli elementi più efficiente rispetto a un normale albero binario.

2. Posso avere nodi con valori duplicati in un albero binario?

Sì, è possibile avere nodi con valori duplicati in un albero binario. Tuttavia, a seconda dell'implementazione e delle regole specifiche dell'albero binario, potrebbero esserci diversi modi per gestire i nodi duplicati. Alcune implementazioni potrebbero consentire duplicati e memorizzarli in qualsiasi ordine, mentre altre potrebbero richiedere che i valori duplicati vengano gestiti in modo specifico o scartati.

3. Come posso rimuovere un nodo specifico da un albero binario?

Per rimuovere un nodo specifico da un albero binario, è necessario seguire questi passaggi:

  1. Trova il nodo che vuoi eliminare utilizzando una ricerca ad albero.
  2. Consideriamo i diversi casi di eliminazione:
    • Se il nodo non ha elementi figlio, puoi semplicemente eliminarlo e liberarne la memoria.
    • Se il nodo ha un solo figlio, è possibile sostituire il nodo con il suo figlio.
    • Se il nodo ha due figli, è necessario trovare il successore più vicino (il nodo più piccolo nel sottoalbero di destra) e sostituire il valore del nodo da eliminare con il valore del successore. Quindi rimuovere il successore dall'albero.
  3. Adatta i collegamenti e i puntatori secondo necessità per mantenere la corretta struttura ad albero.
  5 parti di un algoritmo di programmazione

4. Che cos'è un albero binario completo?

Un albero binario completo è un tipo speciale di albero binario in cui tutti i livelli, tranne forse l'ultimo, sono completamente riempiti e i nodi dell'ultimo livello sono posizionati il ​​più a sinistra possibile. Ciò significa che tutti i nodi hanno due figli, tranne forse i nodi all'ultimo livello, che potrebbero avere uno o nessun figlio.

5. Qual è l'altezza di un albero binario?

L'altezza di un albero binario è la lunghezza del percorso più lungo dalla radice a una foglia. In altre parole, è il numero massimo di spigoli tra la radice e una qualsiasi foglia dell'albero. L'altezza si misura in termini di numero di livelli, quindi un albero con un solo nodo ha altezza 0, mentre un albero vuoto non ha altezza.

6. Quando dovrei utilizzare un albero binario nei miei programmi?

Gli alberi binari sono utili in numerose situazioni. Ecco alcuni casi comuni in cui è possibile utilizzare gli alberi binari:

  • Ricerca efficiente degli elementi: se è necessario cercare rapidamente gli elementi in una struttura dati, un albero binario può fornire un accesso efficiente ai dati.
  • Rappresentazione di relazioni gerarchiche: gli alberi binari sono ideali per rappresentare relazioni gerarchiche, come la struttura delle directory in un File System.
  • Ordinamento dei dati: è possibile utilizzare alberi di ricerca binari per ordinare in modo efficiente i dati ed eseguire ricerche, inserimenti ed eliminazioni in tempo logaritmico.

Ricordatevi di valutare i vostri requisiti e di considerare la complessità delle operazioni sugli alberi binari prima di decidere di utilizzarli nei vostri programmi.

Conclusione

In questa guida completa abbiamo esplorato i concetti fondamentali degli alberi binari in C. Abbiamo appreso la loro struttura, come inserire e rimuovere nodi, eseguire attraversamenti e cercare elementi in un albero binario.

Ci auguriamo che questa guida ti abbia fornito una solida comprensione degli alberi binari e di come implementarli in C. Gli alberi binari sono strutture dati versatili e potenti che possono aiutarti a risolvere un'ampia gamma di problemi di programmazione.

Ricordatevi di esercitarvi e sperimentare con gli esempi forniti per rafforzare la vostra comprensione degli alberi binari in C. Buona fortuna nel vostro percorso di apprendimento e sviluppo del software!