{"id":30530,"date":"2019-10-31T21:36:01","date_gmt":"2019-10-31T18:36:01","guid":{"rendered":"https:\/\/prohoster.info\/blog\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska\/"},"modified":"2019-10-31T21:36:01","modified_gmt":"2019-10-31T18:36:01","slug":"binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska","title":{"rendered":"Albero binario o come creare un albero binario di ricerca","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2>Prelude<\/h2>\n<p>\nQuesto articolo \u00e8 dedicato agli alberi binari di ricerca. Di recente ho scritto un articolo su <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/438512\/\">la compressione dei dati tramite il metodo di Huffman.<\/a><\/noindex> L\u00ec non ho prestato molta attenzione agli alberi binari, poich\u00e9 i metodi di ricerca, inserimento e cancellazione non erano rilevanti. Adesso ho deciso di scrivere un articolo specificamente sugli alberi. Cominciamo. <\/p>\n<p>Un albero \u00e8 una struttura dati composta da nodi connessi da archi. Si pu\u00f2 dire che un albero \u00e8 un caso particolare di grafo. Ecco un esempio di albero: <\/p>\n<p><img decoding=\"async\" alt=\"Albero binario o come creare un albero binario di ricerca\" src=\"\/wp-content\/uploads\/2019\/03\/502ac27f1b93f926c68a68777f6bddd7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nQuesto non \u00e8 un albero binario di ricerca! Tutto sotto il tag!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Terminologia<\/h2>\n<p><\/p>\n<h4>Radice<\/h4>\n<p>\n<i>La radice dell'albero<\/i> \u00e8 il suo nodo pi\u00f9 alto. Nell'esempio, questo \u00e8 il nodo A. Nell'albero, dalla radice a qualsiasi altro nodo pu\u00f2 esserci un solo percorso! In realt\u00e0, ogni nodo pu\u00f2 essere considerato come la radice del relativo sottoalbero.<\/p>\n<h4>Genitori\/Discendenti<\/h4>\n<p>\nTutti i nodi, tranne quello radice, hanno esattamente un arco che sale verso un altro nodo. Il nodo posizionato sopra quello corrente \u00e8 chiamato <i>genitore<\/i> di questo nodo. Un nodo posizionato sotto quello corrente, e connesso a esso, \u00e8 chiamato <i>discendente<\/i> di questo nodo. Prendiamo l'esempio. Prendiamo il nodo B, quindi il suo genitore sar\u00e0 il nodo A, e i suoi figli saranno i nodi D, E e F.<\/p>\n<h4>Foglia<\/h4>\n<p>\nUn nodo che non ha figli sar\u00e0 chiamato foglia dell'albero. Nell'esempio, le foglie saranno i nodi D, E, F, G, I, J, K.<\/p>\n<p>Questa \u00e8 la terminologia di base. Altri concetti saranno trattati in seguito. Quindi, un albero binario \u00e8 un albero in cui ogni nodo pu\u00f2 avere al massimo due figli. Come avete indovinato, l'albero dell'esempio non sar\u00e0 binario, poich\u00e9 i nodi B e H hanno pi\u00f9 di due figli. Ecco un esempio di albero binario:<\/p>\n<p><img decoding=\"async\" alt=\"Albero binario o come creare un albero binario di ricerca\" src=\"\/wp-content\/uploads\/2019\/03\/2f587bd1c428d3850cb0163d6c2984a1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNei nodi dell'albero pu\u00f2 trovarsi qualsiasi informazione. Un albero binario di ricerca \u00e8 un albero binario che ha le seguenti propriet\u00e0:<\/p>\n<ol>\n<li>Entrambi i sottoalberi \u2014 quello sinistro e quello destro \u2014 sono alberi binari di ricerca.<\/li>\n<li>In tutti i nodi del sottoalbero sinistro di un nodo X qualsiasi, i valori delle chiavi dei dati sono minori rispetto al valore della chiave dei dati del nodo X stesso.<\/li>\n<li>In tutti i nodi del sottoalbero destro di un nodo X qualsiasi, i valori delle chiavi dei dati sono maggiori o uguali rispetto al valore della chiave dei dati del nodo X stesso. <\/li>\n<\/ol>\n<p><i>Chiave<\/i> \u2014 qualsiasi caratteristica di un nodo (ad esempio, un numero). La chiave \u00e8 necessaria per poter trovare l'elemento dell'albero corrispondente a questa chiave. Esempio di albero binario di ricerca:<\/p>\n<p><img decoding=\"async\" alt=\"Albero binario o come creare un albero binario di ricerca\" src=\"\/wp-content\/uploads\/2019\/03\/a70ca7d2fdf289b5d1e14bdb4bc38b00.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Rappresentazione dell'albero<\/h2>\n<p>\nMan mano che avanziamo, presenter\u00f2 alcuni (possibilmente incompleti) frammenti di codice per migliorare la vostra comprensione. Il codice completo sar\u00e0 alla fine dell'articolo. <\/p>\n<p>Un albero \u00e8 composto da nodi. Struttura del nodo:<\/p>\n<pre><code class=\"java\">public class Node {\n    private T data;\n    private int key;\n    private Node leftChild;\n    private Node rightChild;\n\n    public Node(T data, int key) {\n        this.data = data;\n        this.key = key;\n    }\n    public Node getLeftChild() {\n        return leftChild;\n    }\n\n    public Node getRightChild() {\n        return rightChild;\n    }\n\/\/...altri metodi del nodo\n}\n<\/code><\/pre>\n<p>\nOgni nodo ha due figli (\u00e8 possibile che i figli leftChild e\/o rightChild contengano il valore null). Probabilmente hai capito che in questo caso il numero data rappresenta i dati memorizzati nel nodo; key \u00e8 la chiave del nodo.<\/p>\n<p>Con il nodo chiarito, ora parliamo delle problematiche attuali sugli alberi. Qui e in seguito, con la parola \"albero\" intender\u00f2 il concetto di albero binario di ricerca. La struttura di un albero binario:<\/p>\n<pre><code class=\"java\">public class BinaryTree {\n     private Node root;\n\n    \/\/metodi dell'albero\n}\n<\/code><\/pre>\n<p>Come classe, avremo bisogno solo della radice dell'albero, poich\u00e9 dalla radice possiamo accedere a qualsiasi nodo dell'albero utilizzando i metodi getLeftChild() e getRightChild().<\/p>\n<h2>Algoritmi negli alberi<\/h2>\n<p><\/p>\n<h3>\u041f\u043e\u0438\u0441\u043a<\/h3>\n<p>\nSupponiamo di avere un albero costruito. Come trovare l'elemento con la chiave key? Dobbiamo spostarci dalla radice verso il basso nell'albero e confrontare il valore di key con la chiave del nodo corrente: se key \u00e8 minore della chiave del nodo corrente, passiamo al figlio sinistro del nodo; se \u00e8 maggiore, passiamo a quello destro; se le chiavi sono uguali, il nodo ricercato \u00e8 stato trovato! Ecco il codice corrispondente:<\/p>\n<pre><code class=\"java\">public Node&lt;T&gt; find(int key) {\n    Node&lt;T&gt; current = root;\n    while (current.getKey() != key) {\n        if (key &lt; current.getKey())\n            current = current.getLeftChild();\n        else\n            current = current.getRightChild();\n        if (current == null)\n            return null;\n    }\n    return current;\n}\n<\/code><\/pre>\n<p>\nSe current diventa uguale a null, significa che l'iterazione ha raggiunto la fine dell'albero (a livello concettuale ti trovi in un luogo non esistente dell'albero \u2014 nel figlio di una foglia).<\/p>\n<p>Esaminiamo l'efficienza dell'algoritmo di ricerca su un albero bilanciato (un albero in cui i nodi sono distribuiti in modo piuttosto uniforme). In questo caso, l'efficienza della ricerca sar\u00e0 O(log(n)), dove il logaritmo \u00e8 in base 2. Osservate: se in un albero bilanciato ci sono n elementi, ci\u00f2 significa che ci saranno log(n) livelli dell'albero in base 2. Nella ricerca, ad ogni passo del ciclo si scende di un livello.<\/p>\n<h3>Inserimento<\/h3>\n<p>\nSe avete afferrato il concetto di ricerca, capire l'inserimento non sar\u00e0 difficile. Bisogna semplicemente scendere fino alla foglia dell'albero (seguendo le regole di discesa descritte nella ricerca) e diventare un suo discendente: sinistro o destro, a seconda della chiave. Implementazione:<\/p>\n<pre><code class=\"java\">   public void insert(T insertData, int key) {\n        Node current = root;\n        Node parent;\n        Node newNode = new Node(insertData, key);\n        if (root == null)\n            root = newNode;\n        else {\n            while (true) {\n                parent = current;\n                if (key &lt; current.getKey()) {\n                    current = current.getLeftChild();\n                    if (current == null) {\n                         parent.setLeftChild(newNode);\n                         return;\n                    }\n                }\n                else {\n                    current = current.getRightChild();\n                    if (current == null) {\n                        parent.setRightChild(newNode);\n                        return;\n                    }\n                }\n            }\n        }\n    }\n<\/code><\/pre>\n<p>\nIn questo caso, oltre al nodo corrente, \u00e8 necessario memorizzare le informazioni sul genitore del nodo attuale. Quando current diventa uguale a null, nella variabile parent ci sar\u00e0 il nodo foglia di cui abbiamo bisogno. <br \/>\nL'efficienza dell'inserimento, ovviamente, sar\u00e0 la stessa della ricerca \u2014 O(log(n)).<\/p>\n<h3>Eliminazione<\/h3>\n<p>\nLa cancellazione \u00e8 l'operazione pi\u00f9 complessa da effettuare con un albero. \u00c8 chiaro che prima dovremo trovare l'elemento che intendiamo rimuovere. Ma cosa succede dopo? Se assegniamo semplicemente il valore null al suo riferimento, perderemo le informazioni sul sottoalbero di cui questo nodo \u00e8 la radice. I metodi di cancellazione dell'albero si dividono in tre casi.<\/p>\n<h4>Primo caso. Il nodo da eliminare non ha discendenti.<\/h4>\n<p>\nSe il nodo da eliminare non ha discendenti, significa che \u00e8 una foglia. Pertanto, possiamo semplicemente assegnare il valore null ai campi leftChild o rightChild del suo genitore. <\/p>\n<h4>Secondo caso. Il nodo da eliminare ha un discendente.<\/h4>\n<p>\nQuesto caso non \u00e8 molto complicato. Torniamo al nostro esempio. Supponiamo di dover rimuovere un elemento con chiave 14. Considerate che essendo un discendente destro del nodo con chiave 10, qualsiasi suo discendente (in questo caso il destro) avr\u00e0 una chiave maggiore di 10, quindi pu\u00f2 essere facilmente \"rimosso\" dall'albero, e il padre pu\u00f2 collegarsi direttamente con il discendente del nodo rimosso, cio\u00e8 il nodo con chiave 10 si collegher\u00e0 al nodo 13. La situazione sarebbe analoga se dovessimo rimuovere un nodo che \u00e8 un discendente sinistro del suo genitore. Pensateci da soli: \u00e8 un'analogia precisa. <\/p>\n<h4>Terzo caso. Un nodo ha due discendenti.<\/h4>\n<p>\nIl caso pi\u00f9 complesso. Analizziamo un nuovo esempio.<\/p>\n<p><img decoding=\"async\" alt=\"Albero binario o come creare un albero binario di ricerca\" src=\"\/wp-content\/uploads\/2019\/03\/0d600478e4a046ae6f7267be49b231bc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h4>Ricerca del successore<\/h4>\n<p>\n Supponiamo di dover rimuovere un nodo con chiave 25. Chi metteremo al suo posto? Qualcuno dei suoi successori (discendenti o discendenti dei discendenti) deve diventare <i>successore<\/i>(colui che occuper\u00e0 il posto del nodo rimosso). <\/p>\n<p>Come capire chi deve diventare il successore? \u00c8 intuitivamente chiaro che si tratta di un nodo nell'albero, la cui chiave \u00e8 la pi\u00f9 vicina in valore a quella del nodo da rimuovere. L'algoritmo \u00e8 il seguente. Bisogna andare al suo discendente destro (sempre a destra, poich\u00e9 si \u00e8 gi\u00e0 detto che la chiave del successore \u00e8 maggiore di quella del nodo eliminato) e poi percorrere la catena dei discendenti sinistri di questo discendente destro. Nell'esempio dobbiamo recarci al nodo con chiave 35 e poi scendere fino a una foglia attraverso la catena dei suoi discendenti sinistri \u2014 in questo caso, questa catena \u00e8 costituita solo dal nodo con chiave 30. In senso stretto, stiamo cercando il nodo pi\u00f9 piccolo in un insieme di nodi che sono maggiori del nodo cercato.<\/p>\n<p><img decoding=\"async\" alt=\"Albero binario o come creare un albero binario di ricerca\" src=\"\/wp-content\/uploads\/2019\/03\/50c4e3e49111eec9e1fd13083ee9b9b0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCodice del metodo di ricerca del successore:<\/p>\n<pre><code class=\"java\">    public Node&lt;T&gt; getSuccessor(Node&lt;T&gt; deleteNode) {\n        Node&lt;T&gt; parentSuccessor = deleteNode; \/\/ genitore del successore\n        Node&lt;T&gt; successor = deleteNode; \/\/ successore\n        Node&lt;T&gt; current = successor.getRightChild(); \/\/ nodo \"iterativo\"\n        while (current != null) {\n            parentSuccessor = successor;\n            successor = current;\n            current = current.getLeftChild();\n        }\n        \/\/ uscendo dal ciclo abbiamo successore e genitore del successore\n        if (successor != deleteNode.getRightChild()) { \/\/ se il successore non corrisponde al nodo destro del nodo da eliminare\n            parentSuccessor.setLeftChild(successor.getRightChild()); \/\/ il suo genitore prende il discendente del successore, per non perderlo\n            successor.setRightChild(deleteNode.getRightChild()); \/\/ collegare il successore con il nodo destro del nodo da eliminare\n        }\n        return successor;\n    }\n<\/code><\/pre>\n<p>\nCodice completo del metodo delete:<\/p>\n<pre><code class=\"java\">public boolean delete(int deleteKey) {\n        Node current = root;\n        Node parent = current;\n        boolean isLeftChild = false; \/\/ In base a se il nodo da eliminare \u00e8 un figlio sinistro o destro, la variabile booleana isLeftChild assumer\u00e0 il valore true o false rispettivamente.\n        while (current.getKey() != deleteKey) {\n            parent = current;\n            if (deleteKey &lt; current.getKey()) {\n                current = current.getLeftChild();\n                isLeftChild = true;\n            } else {\n                isLeftChild = false;\n                current = current.getRightChild();\n            }\n            if (current == null)\n                return false;\n        }\n\n        if (current.getLeftChild() == null &amp;&amp; current.getRightChild() == null) { \/\/ primo caso\n            if (current == root)\n                current = null;\n            else if (isLeftChild)\n                parent.setLeftChild(null);\n            else\n                parent.setRightChild(null);\n        }\n        else if (current.getRightChild() == null) { \/\/ secondo caso\n            if (current == root)\n                root = current.getLeftChild();\n            else if (isLeftChild)\n                parent.setLeftChild(current.getLeftChild());\n            else\n                current.setRightChild(current.getLeftChild());\n        } else if (current.getLeftChild() == null) {\n            if (current == root)\n                root = current.getRightChild();\n            else if (isLeftChild)\n                parent.setLeftChild(current.getRightChild());\n            else\n                parent.setRightChild(current.getRightChild());\n        } \n        else { \/\/ terzo caso\n            Node successor = getSuccessor(current);\n            if (current == root)\n                root = successor;\n            else if (isLeftChild)\n                parent.setLeftChild(successor);\n            else\n                parent.setRightChild(successor);\n        }\n        return true;\n    }\n<\/code><\/pre>\n<p>\nLa complessit\u00e0 pu\u00f2 essere approssimata a O(log(n)).<\/p>\n<h3>Ricerca del massimo\/minimo nell'albero<\/h3>\n<p>\n\u00c8 ovvio come trovare il valore minimo\/massimo nell'albero: si deve passare in sequenza lungo la catena degli elementi sinistri\/destri dell'albero; quando si raggiunge una foglia, essa sar\u00e0 l'elemento minimo\/massimo.<\/p>\n<pre><code class=\"java\">    public Node&lt;T&gt; getMinimum(Node&lt;T&gt; startPoint) {\n        Node&lt;T&gt; current = startPoint;\n        Node&lt;T&gt; parent = current;\n        while (current != null) {\n            parent = current;\n            current = current.getLeftChild();\n        }\n        return parent;\n    }\n\n    public Node&lt;T&gt; getMaximum(Node&lt;T&gt; startPoint) {\n        Node&lt;T&gt; current = startPoint;\n        Node&lt;T&gt; parent = current;\n        while (current != null) {\n            parent = current;\n            current = current.getRightChild();\n        }\n        return parent;\n    }\n<\/code><\/pre>\n<p>\nLa complessit\u00e0 \u00e8 O(log(n))<\/p>\n<h3>Attraversamento simmetrico<\/h3>\n<p>\nL'attraversamento \u00e8 la visita di ciascun nodo dell'albero per compiere un'azione su di esso.<\/p>\n<p>Algoritmo di attraversamento simmetrico ricorsivo:<\/p>\n<ol>\n<li>Compiere un'azione sul figlio sinistro<\/li>\n<li>Compiere un'azione su se stessi<\/li>\n<li>Compiere un'azione sul figlio destro<\/li>\n<\/ol>\n<p>\nCodice:<\/p>\n<pre><code class=\"java\">    public void inOrder(Node&lt;T&gt; current) {\n        if (current != null) {\n            inOrder(current.getLeftChild());\n            System.out.println(current.getData() + \" \");\/\/Qui pu\u00f2 esserci qualsiasi cosa\n            inOrder(current.getRightChild());\n        }\n    }\n<\/code><\/pre>\n<p><\/p>\n<h2>Conclusione<\/h2>\n<p>\nFinalmente! Se ho omesso qualcosa o se ci sono osservazioni, aspetto i vostri commenti. Come promesso, ecco il codice completo.<\/p>\n<p>Node.java:<\/p>\n<pre><code class=\"java\">public class Node&lt;T&gt; {\n    private T data;\n    private int key;\n    private Node&lt;T&gt; leftChild;\n    private Node&lt;T&gt; rightChild;\n\n    public Node(T data, int key) {\n        this.data = data;\n        this.key = key;\n    }\n\n    public void setLeftChild(Node&lt;T&gt; newNode) {\n        leftChild = newNode;\n    }\n\n    public void setRightChild(Node&lt;T&gt; newNode) {\n        rightChild = newNode;\n    }\n\n    public Node&lt;T&gt; getLeftChild() {\n        return leftChild;\n    }\n\n    public Node&lt;T&gt; getRightChild() {\n        return rightChild;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public int getKey() {\n        return key;\n    }\n}\n\n<\/code><\/pre>\n<p>\nBinaryTree.java:<\/p>\n<pre><code class=\"java\">public class BinaryTree&lt;T&gt; {\n    private Node&lt;T&gt; root;\n\n    public Node&lt;T&gt; find(int key) {\n        Node&lt;T&gt; current = root;\n        while (current.getKey() != key) {\n            if (key &lt; current.getKey())\n                current = current.getLeftChild();\n            else\n                current = current.getRightChild();\n            if (current == null)\n                return null;\n        }\n        return current;\n    }\n\n    public void insert(T insertData, int key) {\n        Node&lt;T&gt; current = root;\n        Node&lt;T&gt; parent;\n        Node&lt;T&gt; newNode = new Node&lt;&gt;(insertData, key);\n        if (root == null)\n            root = newNode;\n        else {\n            while (true) {\n                parent = current;\n                if (key &lt; current.getKey()) {\n                    current = current.getLeftChild();\n                    if (current == null) {\n                         parent.setLeftChild(newNode);\n                         return;\n                    }\n                }\n                else {\n                    current = current.getRightChild();\n                    if (current == null) {\n                        parent.setRightChild(newNode);\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    public Node&lt;T&gt; getMinimum(Node&lt;T&gt; startPoint) {\n        Node&lt;T&gt; current = startPoint;\n        Node&lt;T&gt; parent = current;\n        while (current != null) {\n            parent = current;\n            current = current.getLeftChild();\n        }\n        return parent;\n    }\n\n    public Node&lt;T&gt; getMaximum(Node&lt;T&gt; startPoint) {\n        Node&lt;T&gt; current = startPoint;\n        Node&lt;T&gt; parent = current;\n        while (current != null) {\n            parent = current;\n            current = current.getRightChild();\n        }\n        return parent;\n    }\n\n    public Node&lt;T&gt; getSuccessor(Node&lt;T&gt; deleteNode) {\n        Node&lt;T&gt; parentSuccessor = deleteNode;\n        Node&lt;T&gt; successor = deleteNode;\n        Node&lt;T&gt; current = successor.getRightChild();\n        while (current != null) {\n            parentSuccessor = successor;\n            successor = current;\n            current = current.getLeftChild();\n        }\n\n        if (successor != deleteNode.getRightChild()) {\n            parentSuccessor.setLeftChild(successor.getRightChild());\n            successor.setRightChild(deleteNode.getRightChild());\n        }\n        return successor;\n    }\n\n    public boolean delete(int deleteKey) {\n        Node&lt;T&gt; current = root;\n        Node&lt;T&gt; parent = current;\n        boolean isLeftChild = false;\n        while (current.getKey() != deleteKey) {\n            parent = current;\n            if (deleteKey &lt; current.getKey()) {\n                current = current.getLeftChild();\n                isLeftChild = true;\n            } else {\n                isLeftChild = false;\n                current = current.getRightChild();\n            }\n            if (current == null)\n                return false;\n        }\n\n        if (current.getLeftChild() == null &amp;&amp; current.getRightChild() == null) {\n            if (current == root)\n                current = null;\n            else if (isLeftChild)\n                parent.setLeftChild(null);\n            else\n                parent.setRightChild(null);\n        }\n        else if (current.getRightChild() == null) {\n            if (current == root)\n                root = current.getLeftChild();\n            else if (isLeftChild)\n                parent.setLeftChild(current.getLeftChild());\n            else\n                current.setRightChild(current.getLeftChild());\n        } else if (current.getLeftChild() == null) {\n            if (current == root)\n                root = current.getRightChild();\n            else if (isLeftChild)\n                parent.setLeftChild(current.getRightChild());\n            else\n                parent.setRightChild(current.getRightChild());\n        } \n        else {\n            Node&lt;T&gt; successor = getSuccessor(current);\n            if (current == root)\n                root = successor;\n            else if (isLeftChild)\n                parent.setLeftChild(successor);\n            else\n                parent.setRightChild(successor);\n        }\n        return true;\n    }\n\n    public void inOrder(Node&lt;T&gt; current) {\n        if (current != null) {\n            inOrder(current.getLeftChild());\n            System.out.println(current.getData() + \" \");\n            inOrder(current.getRightChild());\n        }\n    }\n}\n<\/code><\/pre>\n<h2>P.S.<\/h2>\n<p><\/p>\n<h3>Degrado a O(n)<\/h3>\n<p>\nMolti di voi potrebbero aver notato: e se facessimo in modo che l'albero diventasse sbilanciato? Ad esempio, inserendo nell'albero nodi con chiavi crescenti: 1,2,3,4,5,6\u2026 Allora l'albero assomiglier\u00e0 a una lista collegata. E s\u00ec, l'albero perder\u00e0 la sua struttura ad albero, e di conseguenza anche l'efficienza nell'accesso ai dati. La complessit\u00e0 delle operazioni di ricerca, inserimento e rimozione diventer\u00e0 quella di una lista collegata: O(n). Questo \u00e8 uno dei pi\u00f9 importanti, a mio parere, svantaggi degli alberi binari.<\/p>\n<p class=\"for_users_only_msg\">Solo gli utenti registrati possono partecipare al sondaggio. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Accedi<\/a><\/noindex>, per favore.<\/p>\n<h2 class=\"default-block__polling-title\">Non sono molto tempo su Habr, e mi piacerebbe sapere su quali argomenti vi piacerebbe vedere pi\u00f9 articoli?<\/h2>\n<ul class=\"content-list content-list_polling\">\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Strutture dati<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Algoritmi (DP, ricorsione, compressione dei dati, ecc.)<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Applicazione di strutture dati e algoritmi nella vita reale<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Programmazione di applicazioni Android in Java<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Programmazione di applicazioni web in Java<\/p>\n<\/li>\n<\/ul>\n<p>    Hanno votato 2 utenti. 1 utente ha votato per astensione.<br \/>\n<br \/>Fonte: habr.com<\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u043b\u044e\u0434\u0438\u044f \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u043c \u0434\u0435\u0440\u0435\u0432\u044c\u044f\u043c \u043f\u043e\u0438\u0441\u043a\u0430. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u0434\u0435\u043b\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u044e \u043f\u0440\u043e \u0441\u0436\u0430\u0442\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0425\u0430\u0444\u0444\u043c\u0430\u043d\u0430. \u0422\u0430\u043c \u044f \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u043b \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0435 \u0434\u0435\u0440\u0435\u0432\u044c\u044f, \u0438\u0431\u043e \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e\u0438\u0441\u043a\u0430, \u0432\u0441\u0442\u0430\u0432\u043a\u0438, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u044b\u043b\u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b. \u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e \u0434\u0435\u0440\u0435\u0432\u044c\u044f. \u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u043d\u0430\u0447\u043d\u0435\u043c. \u0414\u0435\u0440\u0435\u0432\u043e \u2014 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0438\u0437 \u0443\u0437\u043b\u043e\u0432, \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0431\u0440\u0430\u043c\u0438. \u041c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0434\u0435\u0440\u0435\u0432\u043e \u2014 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":22528,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-30530","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u043b\u044e\u0434\u0438\u044f \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u043c \u0434\u0435\u0440\u0435\u0432\u044c\u044f\u043c \u043f\u043e\u0438\u0441\u043a\u0430. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u0434\u0435\u043b\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u044e \u043f\u0440\u043e \u0441\u0436\u0430\u0442\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0425\u0430\u0444\u0444\u043c\u0430\u043d\u0430. \u0422\u0430\u043c \u044f \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u043b \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0435 \u0434\u0435\u0440\u0435\u0432\u044c\u044f, \u0438\u0431\u043e \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e\u0438\u0441\u043a\u0430, \u0432\u0441\u0442\u0430\u0432\u043a\u0438, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u044b\u043b\u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b. \u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e \u0434\u0435\u0440\u0435\u0432\u044c\u044f. \u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u043d\u0430\u0447\u043d\u0435\u043c. \u0414\u0435\u0440\u0435\u0432\u043e \u2014 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0438\u0437 \u0443\u0437\u043b\u043e\u0432, \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0431\u0440\u0430\u043c\u0438. \u041c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0434\u0435\u0440\u0435\u0432\u043e \u2014\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47Binary Tree \u0438\u043b\u0438 \u043a\u0430\u043a \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e \u043f\u043e\u0438\u0441\u043a\u0430 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u043b\u044e\u0434\u0438\u044f \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u043c \u0434\u0435\u0440\u0435\u0432\u044c\u044f\u043c \u043f\u043e\u0438\u0441\u043a\u0430. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u0434\u0435\u043b\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u044e \u043f\u0440\u043e \u0441\u0436\u0430\u0442\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0425\u0430\u0444\u0444\u043c\u0430\u043d\u0430. \u0422\u0430\u043c \u044f \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u043b \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0435 \u0434\u0435\u0440\u0435\u0432\u044c\u044f, \u0438\u0431\u043e \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e\u0438\u0441\u043a\u0430, \u0432\u0441\u0442\u0430\u0432\u043a\u0438, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u044b\u043b\u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b. \u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e \u0434\u0435\u0440\u0435\u0432\u044c\u044f. \u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u043d\u0430\u0447\u043d\u0435\u043c. \u0414\u0435\u0440\u0435\u0432\u043e \u2014 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0438\u0437 \u0443\u0437\u043b\u043e\u0432, \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0431\u0440\u0430\u043c\u0438. \u041c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0434\u0435\u0440\u0435\u0432\u043e \u2014\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:36:01+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:36:01+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Binary Tree o come preparare un albero binario di ricerca | ProHoster","description":"Preludio Questo articolo \u00e8 dedicato agli alberi binari di ricerca. Recentemente ho scritto un articolo sulla compressione dei dati tramite il metodo di Huffman. In quello non ho prestato molta attenzione agli alberi binari, poich\u00e9 i metodi di ricerca, inserimento e cancellazione non erano rilevanti. Ora ho deciso di scrivere un articolo proprio sugli alberi. Cominciamo. Un albero \u00e8 una struttura dati composta da nodi collegati da archi. Si pu\u00f2 dire che un albero \u00e8","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47Binary Tree \u0438\u043b\u0438 \u043a\u0430\u043a \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e \u043f\u043e\u0438\u0441\u043a\u0430 | ProHoster","og:description":"\u041f\u0440\u0435\u043b\u044e\u0434\u0438\u044f \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u043c \u0434\u0435\u0440\u0435\u0432\u044c\u044f\u043c \u043f\u043e\u0438\u0441\u043a\u0430. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u0434\u0435\u043b\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u044e \u043f\u0440\u043e \u0441\u0436\u0430\u0442\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0425\u0430\u0444\u0444\u043c\u0430\u043d\u0430. \u0422\u0430\u043c \u044f \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u043b \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0435 \u0434\u0435\u0440\u0435\u0432\u044c\u044f, \u0438\u0431\u043e \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e\u0438\u0441\u043a\u0430, \u0432\u0441\u0442\u0430\u0432\u043a\u0438, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u044b\u043b\u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b. \u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e \u0434\u0435\u0440\u0435\u0432\u044c\u044f. \u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u043d\u0430\u0447\u043d\u0435\u043c. \u0414\u0435\u0440\u0435\u0432\u043e \u2014 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0438\u0437 \u0443\u0437\u043b\u043e\u0432, \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0431\u0440\u0430\u043c\u0438. \u041c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0434\u0435\u0440\u0435\u0432\u043e \u2014","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:36:01+00:00","article:modified_time":"2019-10-31T18:36:01+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"30530","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 01:39:20","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:33:27","updated":"2026-01-21 01:39:20","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/30530","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=30530"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/30530\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/22528"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=30530"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=30530"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=30530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}