Quali sono le applicazioni degli alberi binari?


323

Mi chiedo quali siano le particolari applicazioni degli alberi binari. Potresti dare alcuni esempi reali?

Risposte:


425

Litigare sulle prestazioni degli alberi binari non ha senso: non sono una struttura di dati, ma una famiglia di strutture di dati, tutte con caratteristiche di prestazione diverse. Mentre è vero che gli alberi binari sbilanciati si comportano molto peggio degli alberi binari autobilanciati per la ricerca, ci sono molti alberi binari (come i tentativi binari) per i quali "bilanciamento" non ha alcun significato.

Applicazioni di alberi binari

  • Albero di ricerca binario - Utilizzato in molte applicazioni di ricerca in cui i dati vengono costantemente immessi / usciti, come gli oggetti mape setnelle librerie di molte lingue.
  • Binary Space Partition - Utilizzato in quasi tutti i videogiochi 3D per determinare quali oggetti devono essere renderizzati.
  • Tentativi binari : utilizzati in quasi tutti i router ad alta larghezza di banda per l'archiviazione delle tabelle dei router.
  • Hash Trees : utilizzati nei programmi p2p e nelle firme di immagini specializzate in cui è necessario verificare un hash, ma l'intero file non è disponibile.
  • Heap - Utilizzato nell'implementazione di code di priorità efficienti, che a loro volta vengono utilizzate per la pianificazione di processi in molti sistemi operativi, Qualità del servizio nei router e A * (algoritmo di rilevamento del percorso utilizzato nelle applicazioni AI, inclusi robotica e videogiochi) . Utilizzato anche in heap-sort.
  • Huffman Coding Tree ( Chip Uni ) - utilizzato negli algoritmi di compressione, come quelli utilizzati dai formati di file .jpeg e .mp3.
  • Alberi GGM : utilizzati nelle applicazioni crittografiche per generare un albero di numeri pseudo-casuali.
  • Albero di sintassi - Costruito da compilatori e calcolatori (implicitamente) per analizzare le espressioni.
  • Treap : struttura di dati randomizzata utilizzata in reti wireless e allocazione della memoria.
  • T-tree - Sebbene la maggior parte dei database utilizzi una qualche forma di B-tree per archiviare i dati sull'unità, i database che mantengono tutti (la maggior parte) i loro dati in memoria spesso usano T-tree per farlo.

Il motivo per cui gli alberi binari vengono utilizzati più spesso degli alberi n-ary per la ricerca è che gli alberi n-ary sono più complessi, ma di solito non offrono un reale vantaggio di velocità.

In un albero binario (bilanciato) con mnodi, passare da un livello all'altro richiede un confronto e ci sono log_2(m)livelli, per un totale di log_2(m)confronti.

Al contrario, un albero n-ary richiederà log_2(n)confronti (usando una ricerca binaria) per passare al livello successivo. Poiché ci sono log_n(m)livelli totali, la ricerca richiederà log_2(n)*log_n(m)= log_2(m)confronti totali. Quindi, sebbene gli alberi n-ary siano più complessi, non offrono alcun vantaggio in termini di confronti totali necessari.

(Tuttavia, gli alberi n-ary sono ancora utili in situazioni di nicchia. Gli esempi che vengono immediatamente in mente sono quad-alberi e altri alberi di partizione spaziale, in cui la divisione dello spazio usando solo due nodi per livello renderebbe inutilmente complessa la logica; e B-alberi utilizzati in molti database, in cui il fattore limitante non è il numero di confronti effettuati a ciascun livello, ma quanti nodi possono essere caricati dal disco rigido contemporaneamente)


3
> Treap: struttura di dati randomizzata utilizzata nella rete wireless e nell'allocazione della memoria. Come vengono utilizzati esattamente nell'allocazione della memoria e nella rete wireless?
FRP

1
Esistono molte utili strutture di dati e algoritmi che fanno uso della parola "binario", e "albero di ricerca binario" è in effetti uno di questi, ma non è questa la domanda che è stata posta. A che serve un semplice "albero binario", non uno ordinato, non equilibrato, non completo. Solo un semplice vecchio albero casuale?
Michael Erickson,

4
@MichaelErickson Hai letto la risposta? Perché questa è esattamente la domanda a cui ho risposto.
BlueRaja - Danny Pflughoeft,

1
Credo che gli Hash Tree siano comunemente chiamati Merkle Tree, almeno all'interno delle comunità bitcoin ed ethereum, IPFS, ecc.
Duke,

1
Peccato che questa risposta contenga così tanti errori. Gli alberi n-ary su hardware moderno sono quasi sempre preferibili agli alberi binari. Le applicazioni denominate principalmente non usano alberi binari.
Stephan Eggermont,

290

Quando la maggior parte delle persone parla di alberi binari, molto spesso non pensa agli alberi di ricerca binari , quindi lo tratterò per primo.

Un albero di ricerca binaria non bilanciato è in realtà utile per poco più che educare gli studenti sulle strutture di dati. Questo perché, a meno che i dati non arrivino in un ordine relativamente casuale, l'albero può facilmente degenerare nella sua forma peggiore, che è un elenco collegato, poiché i semplici alberi binari non sono bilanciati.

Un buon esempio: una volta ho dovuto riparare alcuni software che caricavano i suoi dati in un albero binario per la manipolazione e la ricerca. Ha scritto i dati in forma ordinata:

Alice
Bob
Chloe
David
Edwina
Frank

in modo che, quando lo rileggevo, finiva con il seguente albero:

  Alice
 /     \
=       Bob
       /   \
      =     Chloe
           /     \
          =       David
                 /     \
                =       Edwina
                       /      \
                      =        Frank
                              /     \
                             =       =

che è la forma degenerata. Se vai a cercare Frank in quell'albero, dovrai cercare tutti e sei i nodi prima di trovarlo.

Gli alberi binari diventano veramente utili per la ricerca quando li equilibrate. Ciò comporta la rotazione di alberi secondari attraverso il loro nodo radice in modo che la differenza di altezza tra due alberi secondari sia minore o uguale a 1. L'aggiunta di quei nomi sopra uno alla volta in un albero bilanciato ti darebbe la seguente sequenza:

1.   Alice
    /     \
   =       =

 

2.   Alice
    /     \
   =       Bob
          /   \
         =     =

 

3.        Bob
        _/   \_
   Alice       Chloe
  /     \     /     \
 =       =   =       =

 

4.        Bob
        _/   \_
   Alice       Chloe
  /     \     /     \
 =       =   =       David
                    /     \
                   =       =

 

5.           Bob
        ____/   \____
   Alice             David
  /     \           /     \
 =       =     Chloe       Edwina
              /     \     /      \
             =       =   =        =

 

6.              Chloe
            ___/     \___
         Bob             Edwina
        /   \           /      \
   Alice     =      David        Frank
  /     \          /     \      /     \
 =       =        =       =    =       =

Puoi effettivamente vedere interi sotto-alberi che ruotano a sinistra (nei passaggi 3 e 6) quando vengono aggiunte le voci e questo ti dà un albero binario bilanciato in cui la ricerca nel caso peggiore è O(log N)piuttosto che la O(N) che dà la forma degenerata. In nessun caso il NULL ( =) più alto differisce dal più basso di più di un livello. E, nella struttura finale di cui sopra, è possibile trovare Frank da solo guardando tre nodi ( Chloe, Edwinae, infine, Frank).

Certo, possono diventare ancora più utili quando si creano alberi bilanciati a più vie invece di alberi binari. Ciò significa che ogni nodo contiene più di un oggetto (tecnicamente, contengono N oggetti e N + 1 puntatori, un albero binario è un caso speciale di un albero a più vie a 1 via con 1 oggetto e 2 puntatori).

Con un albero a tre vie, si finisce con:

  Alice Bob Chloe
 /     |   |     \
=      =   =      David Edwina Frank
                 /     |      |     \
                =      =      =      =

Questo è in genere utilizzato nel mantenimento delle chiavi per un indice di elementi. Ho scritto un software di database ottimizzato per l'hardware in cui un nodo ha esattamente le dimensioni di un blocco del disco (diciamo 512 byte) e metti quante più chiavi possibile in un singolo nodo. I puntatori in questo caso erano in realtà numeri di record in un file di accesso diretto a lunghezza fissa separato dal file di indice (quindi è Xpossibile trovare il numero di record semplicemente cercando di X * record_length).

Ad esempio, se i puntatori sono 4 byte e la dimensione della chiave è 10, il numero di chiavi in ​​un nodo da 512 byte è 36. Sono 36 chiavi (360 byte) e 37 puntatori (148 byte) per un totale di 508 byte con 4 byte sprecati per nodo.

L'uso di chiavi a più vie introduce la complessità di una ricerca a due fasi (ricerca a più vie per trovare il nodo corretto combinato con una piccola ricerca sequenziale (o binaria lineare) per trovare la chiave corretta nel nodo) ma il vantaggio in fare meno I / O su disco più che compensare questo.

Non vedo alcun motivo per farlo per una struttura in memoria, sarebbe meglio attenersi a un albero binario bilanciato e mantenere semplice il codice.

Inoltre, tieni presente che i vantaggi di O(log N)over O(N)non appaiono davvero quando i tuoi set di dati sono piccoli. Se stai usando un albero a più vie per memorizzare le quindici persone nella tua rubrica, è probabilmente eccessivo. I vantaggi derivano dalla memorizzazione di qualcosa come ogni ordine dei tuoi centomila clienti negli ultimi dieci anni.

Il punto centrale della notazione big-O è indicare cosa succede mentre l' Ninfinito si avvicina. Alcune persone potrebbero non essere d'accordo, ma è anche accettabile utilizzare l'ordinamento a bolle se sei sicuro che i set di dati rimarranno al di sotto di una determinata dimensione, a condizione che nient'altro sia prontamente disponibile :-)


Per quanto riguarda altri usi per alberi binari, ce ne sono molti, come:

  • Cumuli binari in cui i tasti più alti sono sopra o uguali a quelli più bassi anziché a sinistra di (o sotto o uguali a e destra);
  • Hash alberi, simili alle tabelle hash;
  • Alberi di sintassi astratti per la compilazione di linguaggi informatici;
  • Alberi di Huffman per la compressione dei dati;
  • Alberi di routing per il traffico di rete.

Vista la quantità di spiegazioni che ho generato per gli alberi di ricerca, sono reticente ad approfondire gli altri, ma dovrebbe bastare a ricercarli, se lo desideri.


28
+1 Per tale risposta scritta; oltre a presentarmi alberi multi-direzionali bilanciati, qualcosa che non avevo mai visto prima.
Tony,

3
Non sono d'accordo con la tua affermazione sul fatto che siano utili solo per educare gli studenti. Sono abbastanza utili, anche come una semplice struttura di dati statici. Tuttavia, questa è una risposta molto ben scritta e illustrata, quindi +1 per tutto il resto. :-)
Benson,

1
Su hardware moderno, quasi tutti gli alberi dovrebbero essere a più vie.
Stephan Eggermont,

89

L'organizzazione del codice Morse è un albero binario.

binary-albero

codice Morse


4
Questa è la mia risposta preferita Illustra direttamente la riduzione della complessità computazionale richiesta per raggiungere ulteriormente i caratteri nell'elenco.
Baffi,

7
Mi è davvero piaciuta questa risposta!
Duncan Edwards,


62

Un albero binario è una struttura di dati ad albero in cui ogni nodo ha al massimo due nodi figlio, generalmente distinti come "sinistra" e "destra". I nodi con figli sono nodi principali e i nodi figlio possono contenere riferimenti ai loro genitori. Fuori dall'albero, c'è spesso un riferimento al nodo "root" (l'antenato di tutti i nodi), se esiste. È possibile raggiungere qualsiasi nodo nella struttura dei dati iniziando dal nodo principale e seguendo ripetutamente i riferimenti al figlio sinistro o destro. In un albero binario un grado di ogni nodo è massimo due.

Albero binario

Gli alberi binari sono utili, perché come puoi vedere nella figura, se vuoi trovare un nodo nell'albero, devi solo guardare un massimo di 6 volte. Se si desidera cercare il nodo 24, ad esempio, si inizierà dalla radice.

  • Il root ha un valore di 31, che è maggiore di 24, quindi vai al nodo di sinistra.
  • Il nodo sinistro ha un valore di 15, che è inferiore a 24, quindi vai al nodo destro.
  • Il nodo destro ha un valore di 23, che è inferiore a 24, quindi vai al nodo giusto.
  • Il nodo destro ha un valore di 27, che è maggiore di 24, quindi vai al nodo sinistro.
  • Il nodo sinistro ha un valore di 25, che è maggiore di 24, quindi vai al nodo sinistro.
  • Il nodo ha un valore di 24, che è la chiave che stiamo cercando.

Questa ricerca è illustrata di seguito: Ricerca dell'albero

Puoi vedere che puoi escludere metà dei nodi dell'intero albero al primo passaggio. e metà della sottostruttura sinistra sul secondo. Questo rende ricerche molto efficaci. Se ciò avvenisse su 4 miliardi di elementi, dovresti cercare solo un massimo di 32 volte. Pertanto, più elementi sono contenuti nella struttura, più efficiente può essere la ricerca.

Le eliminazioni possono diventare complesse. Se il nodo ha 0 o 1 figlio, allora è semplicemente una questione di spostare alcuni puntatori per escludere quello da eliminare. Tuttavia, non è possibile eliminare facilmente un nodo con 2 figli. Quindi prendiamo una scorciatoia. Diciamo che volevamo eliminare il nodo 19.

Elimina 1

Dal momento che cercare di determinare dove spostare i puntatori sinistro e destro non è facile, ne troviamo uno con cui sostituirlo. Andiamo al sottoalbero di sinistra e andiamo il più a destra possibile. Questo ci dà il prossimo valore più grande del nodo che vogliamo eliminare.

Elimina 3

Ora copiamo tutti i contenuti di 18, ad eccezione dei puntatori sinistro e destro, ed eliminiamo il nodo 18 originale.

Elimina 4


Per creare queste immagini, ho implementato un albero AVL, un albero auto-bilanciante, in modo che in ogni momento, l'albero abbia al massimo un livello di differenza tra i nodi foglia (nodi senza figli). Ciò evita che l'albero si inclini e mantiene il O(log n)tempo di ricerca massimo , con il costo di un po 'più di tempo richiesto per inserimenti ed eliminazioni.

Ecco un esempio che mostra come il mio albero AVL si è mantenuto il più compatto ed equilibrato possibile.

inserisci qui la descrizione dell'immagine

In un array ordinato, le ricerche continuerebbero comunque O(log(n)), proprio come un albero, ma l'inserimento e la rimozione casuali richiederebbero O (n) invece dell'albero O(log(n)). Alcuni contenitori STL utilizzano queste caratteristiche prestazionali a proprio vantaggio, pertanto i tempi di inserimento e rimozione richiedono un massimo di O(log n), il che è molto veloce. Alcuni di questi contenitori sono map, multimap, set, e multiset.

Il codice di esempio per un albero AVL è disponibile all'indirizzo http://ideone.com/MheW8


5
Devi solo cercare O (log n) se hai a che fare con un albero di ricerca binario (che è ben bilanciato.) Gli alberi binari arbitrari non hanno vincoli di ordinazione e un BST casuale ha complessità di ricerca O (log h ).
dlev,

Quelli non sono del tipo immagazzinato nei relativi contenitori standard.
Puppy,

12

L'applicazione principale è alberi di ricerca binari . Si tratta di una struttura di dati in cui la ricerca, l'inserimento e la rimozione sono tutti molto rapidi (sulle log(n)operazioni)


1
Gli alberi di ricerca binari non sono un'applicazione ma sono un tipo particolare di albero binario.
nbro,

@nbro: Stai discutendo di una semantica senza senso, entrambi sono modi validi per dire la stessa cosa. Nota che "applicazione" qui non significa la stessa cosa di "applicazione per computer"
BlueRaja - Danny Pflughoeft

Penso che la domanda fosse più legata alle applicazioni del mondo reale e non a implementazioni specifiche o particolari tipi di alberi binari. E a proposito, l'interrogante non sta chiedendo quali strutture di dati siano particolari alberi binari. Non ha senso, IMO. Ma sono d'accordo è comunque ambiguo. Ad esempio, nell'altra tua risposta, menzioni gli alberi di sintassi, che è un'applicazione della struttura dei dati dell'albero (ma non necessariamente binaria ) in un'applicazione reale. Sulla base del tuo ragionamento, quindi potrei elencare tutti gli alberi binari che conosco, saremmo tutti felici per la quantità di oggetti.
nbro,


11

Un esempio interessante di un albero binario che non è stato menzionato è quello di un'espressione matematica valutata in modo ricorsivo. Fondamentalmente è inutile dal punto di vista pratico, ma è un modo interessante di pensare a tali espressioni.

Fondamentalmente ogni nodo dell'albero ha un valore che è inerente a se stesso o viene valutato ricorsivamente operando sui valori dei suoi figli.

Ad esempio, l'espressione (1+3)*2può essere espressa come:

    *
   / \
  +   2
 / \
1   3

Per valutare l'espressione, chiediamo il valore del genitore. Questo nodo a sua volta ottiene i suoi valori dai suoi figli, un operatore più e un nodo che contiene semplicemente "2". L'operatore plus a sua volta ottiene i suoi valori dai bambini con i valori '1' e '3' e li aggiunge, restituendo 4 al nodo di moltiplicazione che restituisce 8.

Questo uso di un albero binario è simile a invertire la notazione polacca in un certo senso, in quanto l'ordine in cui vengono eseguite le operazioni è identico. Inoltre, una cosa da notare è che non deve necessariamente essere un albero binario, è solo che gli operatori più comunemente usati sono binari. Al suo livello più elementare, l'albero binario qui è in realtà solo un linguaggio di programmazione puramente funzionale molto semplice.



9

Non credo che ci sia alcun uso per alberi binari "puri". (tranne per scopi didattici) Alberi binari bilanciati, come alberi rosso-neri o alberi AVL sono molto più utili, perché garantiscono operazioni O (logn). Gli alberi binari normali possono finire per essere un elenco (o quasi un elenco) e non sono molto utili nelle applicazioni che utilizzano molti dati.

Gli alberi bilanciati vengono spesso utilizzati per implementare mappe o set. Possono anche essere utilizzati per l'ordinamento in O (nlogn), anche se esistono modi migliori per farlo.

Anche per la ricerca / inserimento / eliminazione possono essere utilizzate tabelle hash , che di solito hanno prestazioni migliori rispetto agli alberi di ricerca binari (bilanciati o meno).

Un'applicazione in cui sarebbero utili alberi di ricerca binaria (bilanciata) sarebbe se fossero necessarie la ricerca / l'inserimento / la cancellazione e l'ordinamento. L'ordinamento potrebbe essere sul posto (quasi, ignorando lo spazio dello stack necessario per la ricorsione), dato un albero bilanciato di build pronto. Sarebbe comunque O (nlogn) ma con un fattore costante più piccolo e senza spazio aggiuntivo necessario (ad eccezione del nuovo array, supponendo che i dati debbano essere inseriti in un array). Le tabelle hash invece non possono essere ordinate (almeno non direttamente).

Forse sono utili anche in alcuni sofisticati algoritmi per fare qualcosa, ma non mi viene in mente nulla. Se ne trovo di più, modificherò il mio post.

Altri alberi come gli alberi B + sono ampiamente utilizzati nei database


9

Una delle applicazioni più comuni è l'archiviazione efficiente dei dati in forma ordinata per accedere e cercare rapidamente gli elementi memorizzati. Ad esempio, std::mapo std::setnella libreria standard C ++.

L'albero binario come struttura di dati è utile per varie implementazioni di parser di espressioni e risolutori di espressioni.

Può anche essere utilizzato per risolvere alcuni problemi del database, ad esempio l'indicizzazione.

Generalmente, l'albero binario è un concetto generale di una particolare struttura di dati basata su alberi e possono essere costruiti vari tipi specifici di alberi binari con proprietà diverse.


7

In C ++ STL e molte altre librerie standard in altre lingue, come Java e C #. Gli alberi di ricerca binaria vengono utilizzati per implementare set e mappa.


2
in realtà in insiemi / mappe C ++ si basano più comunemente su alberi rosso-neri, che è un albero di ricerca binario con un paio di restrizioni in più.
Idan K,

6

Una delle applicazioni più importanti degli alberi binari sono gli alberi di ricerca binaria bilanciati come:

Questo tipo di alberi ha la proprietà che la differenza nelle altezze della sottostruttura sinistra e della sottostruttura destra viene mantenuta ridotta eseguendo operazioni come le rotazioni ogni volta che un nodo viene inserito o eliminato.

Per questo motivo, l'altezza complessiva dell'albero rimane dell'ordine del registro n e le operazioni come la ricerca, l'inserimento e la cancellazione dei nodi vengono eseguite nel tempo O (registro n). L'STL di C ++ implementa anche questi alberi sotto forma di insiemi e mappe.


5

Possono essere utilizzati come modo rapido per ordinare i dati. Inserire i dati in un albero di ricerca binario in O (log (n)). Quindi attraversare l'albero per ordinarli.


2

la sintassi dei programmi, o per questo motivo molte altre cose come i linguaggi naturali possono essere analizzate usando l'albero binario (anche se non necessariamente).



2

Sull'hardware moderno, un albero binario è quasi sempre non ottimale a causa della cattiva gestione della cache e dello spazio. Questo vale anche per le varianti (semi) bilanciate. Se li trovi, è dove le prestazioni non contano (o sono dominate dalla funzione di confronto), o più probabilmente per ragioni storiche o di ignoranza.


2
Non ottimale rispetto a cosa?

alberi a più vie. La ricerca lineare attraverso tutti i dati ottenuti da un accesso alla memoria è molto più rapida rispetto a un nuovo accesso alla memoria principale
Stephan Eggermont,

Voglio crederti, ma non c'è nulla nella tua risposta a sostegno delle tue affermazioni. Fonti, notazione grande o qualcosa del genere. Per favore, elabora.
PhilT


0

Un compilatore che utilizza un albero binario per una rappresentazione di un AST, può utilizzare algoritmi noti per analizzare l'albero come postorder, inorder. Il programmatore non ha bisogno di elaborare il proprio algoritmo. Poiché un albero binario per un file sorgente è più alto dell'albero n-ary, la sua costruzione richiede più tempo. Prendi questa produzione: selstmnt: = "if" "(" expr ")" stmnt "ELSE" stmnt In un albero binario avrà 3 livelli di nodi, ma l'albero n-ary avrà 1 livello (di chid)

Ecco perché i sistemi operativi basati su Unix sono lenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.