{"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\/pt\/blog\/administrirovanie\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska","title":{"rendered":"\u00c1rvore Bin\u00e1ria ou como preparar uma \u00e1rvore bin\u00e1ria de busca","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<h2>Prel\u00fadio<\/h2>\n<p>\nEste artigo \u00e9 dedicado a \u00e1rvores bin\u00e1rias de busca. Recentemente fiz um artigo sobre <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/438512\/\">compress\u00e3o de dados pelo m\u00e9todo de Huffman.<\/a><\/noindex> L\u00e1, eu n\u00e3o prestei muita aten\u00e7\u00e3o nas \u00e1rvores bin\u00e1rias, pois os m\u00e9todos de busca, inser\u00e7\u00e3o e dele\u00e7\u00e3o n\u00e3o eram relevantes. Agora decidi escrever um artigo especificamente sobre \u00e1rvores. Vamos come\u00e7ar. <\/p>\n<p>Uma \u00e1rvore \u00e9 uma estrutura de dados composta por n\u00f3s conectados por arestas. Pode-se dizer que uma \u00e1rvore \u00e9 um caso especial de grafo. Aqui est\u00e1 um exemplo de \u00e1rvore: <\/p>\n<p><img decoding=\"async\" alt=\"\u00c1rvore Bin\u00e1ria ou como preparar uma \u00e1rvore bin\u00e1ria de busca\" src=\"\/wp-content\/uploads\/2019\/03\/502ac27f1b93f926c68a68777f6bddd7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEsta n\u00e3o \u00e9 uma \u00e1rvore bin\u00e1ria de busca! Tudo abaixo!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Terminologia<\/h2>\n<p><\/p>\n<h4>Raiz<\/h4>\n<p>\n<i>A raiz da \u00e1rvore<\/i> \u00e9 o n\u00f3 mais alto. No exemplo, \u00e9 o n\u00f3 A. Em uma \u00e1rvore, do n\u00f3 raiz para qualquer outro n\u00f3 pode haver apenas um caminho! Na verdade, qualquer n\u00f3 pode ser visto como a raiz do respectivo sub\u00e1rvore.<\/p>\n<h4>Pais\/filhos<\/h4>\n<p>\nTodos os n\u00f3s, exceto a raiz, t\u00eam exatamente uma aresta que vai para cima em dire\u00e7\u00e3o a outro n\u00f3. O n\u00f3 que est\u00e1 acima do atual \u00e9 chamado de <i>pai<\/i> deste n\u00f3. O n\u00f3 que est\u00e1 abaixo do atual e conectado a ele \u00e9 chamado de <i>filho<\/i> deste n\u00f3. Vamos usar um exemplo. Pegamos o n\u00f3 B, ent\u00e3o seu pai ser\u00e1 o n\u00f3 A, e seus filhos ser\u00e3o os n\u00f3s D, E e F.<\/p>\n<h4>Folha<\/h4>\n<p>\nUm n\u00f3 que n\u00e3o tem filhos ser\u00e1 chamado de folha da \u00e1rvore. No exemplo, as folhas ser\u00e3o os n\u00f3s D, E, F, G, I, J, K.<\/p>\n<p>Esta \u00e9 a terminologia b\u00e1sica. Outros conceitos ser\u00e3o abordados a seguir. Ent\u00e3o, uma \u00e1rvore bin\u00e1ria \u00e9 uma \u00e1rvore em que cada n\u00f3 ter\u00e1 no m\u00e1ximo dois filhos. Como voc\u00ea deve ter adivinhado, a \u00e1rvore do exemplo n\u00e3o \u00e9 bin\u00e1ria, pois os n\u00f3s B e H t\u00eam mais de dois filhos. Aqui est\u00e1 um exemplo de \u00e1rvore bin\u00e1ria:<\/p>\n<p><img decoding=\"async\" alt=\"\u00c1rvore Bin\u00e1ria ou como preparar uma \u00e1rvore bin\u00e1ria de busca\" src=\"\/wp-content\/uploads\/2019\/03\/2f587bd1c428d3850cb0163d6c2984a1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNos n\u00f3s da \u00e1rvore pode haver qualquer informa\u00e7\u00e3o. Uma \u00e1rvore bin\u00e1ria de busca \u00e9 uma \u00e1rvore bin\u00e1ria, para a qual as seguintes propriedades se aplicam:<\/p>\n<ol>\n<li>Ambas as sub\u00e1rvores \u2014 a esquerda e a direita \u2014 s\u00e3o \u00e1rvores bin\u00e1rias de busca.<\/li>\n<li>Todos os n\u00f3s da sub\u00e1rvore esquerda de um n\u00f3 X t\u00eam valores de chave de dados menores do que o valor da chave de dados do pr\u00f3prio n\u00f3 X.<\/li>\n<li>Todos os n\u00f3s da sub\u00e1rvore direita de um n\u00f3 X t\u00eam valores de chave de dados maiores ou iguais ao valor da chave de dados do pr\u00f3prio n\u00f3 X. <\/li>\n<\/ol>\n<p><i>Chave<\/i> \u00e9 uma caracter\u00edstica de um n\u00f3 (por exemplo, um n\u00famero). A chave \u00e9 necess\u00e1ria para que seja poss\u00edvel encontrar o elemento da \u00e1rvore que corresponde a essa chave. Exemplo de \u00e1rvore bin\u00e1ria de busca:<\/p>\n<p><img decoding=\"async\" alt=\"\u00c1rvore Bin\u00e1ria ou como preparar uma \u00e1rvore bin\u00e1ria de busca\" src=\"\/wp-content\/uploads\/2019\/03\/a70ca7d2fdf289b5d1e14bdb4bc38b00.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Representa\u00e7\u00e3o da \u00e1rvore<\/h2>\n<p>\n\u00c0 medida que avan\u00e7amos, apresentarei alguns (possivelmente incompletos) trechos de c\u00f3digo para melhorar sua compreens\u00e3o. O c\u00f3digo completo estar\u00e1 no final do artigo. <\/p>\n<p>Uma \u00e1rvore \u00e9 composta por n\u00f3s. A estrutura de um n\u00f3:<\/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    public Node&lt;T&gt; getLeftChild() {\n        return leftChild;\n    }\n\n    public Node&lt;T&gt; getRightChild() {\n        return rightChild;\n    }\n\/\/ ... outros m\u00e9todos do n\u00f3\n}\n<\/code><\/pre>\n<p>\nCada n\u00f3 tem dois filhos (\u00e9 bem poss\u00edvel que os filhos leftChild e\/ou rightChild contenham o valor null). Voc\u00ea deve ter entendido que, neste caso, data \u00e9 os dados armazenados no n\u00f3; key \u00e9 a chave do n\u00f3.<\/p>\n<p>Compreendido o n\u00f3, agora vamos falar sobre problemas pr\u00e1ticos relacionados a \u00e1rvores. Daqui em diante, quando eu mencionar \u2018\u00e1rvore\u2019, estarei me referindo a uma \u00e1rvore bin\u00e1ria de busca. A estrutura de uma \u00e1rvore bin\u00e1ria:<\/p>\n<pre><code class=\"java\">public class BinaryTree&lt;T&gt; {\n     private Node&lt;T&gt; root;\n\n    \/\/ m\u00e9todos da \u00e1rvore\n}\n<\/code><\/pre>\n<p>Como campo da classe, precisamos apenas da raiz da \u00e1rvore, pois, a partir da raiz, utilizando os m\u00e9todos getLeftChild() e getRightChild(), \u00e9 poss\u00edvel acessar qualquer n\u00f3 da \u00e1rvore.<\/p>\n<h2>Algoritmos na \u00e1rvore<\/h2>\n<p><\/p>\n<h3>A busca<\/h3>\n<p>\nSuponha que voc\u00ea tenha uma \u00e1rvore constru\u00edda. Como encontrar o elemento com a chave key? \u00c9 necess\u00e1rio percorrer a \u00e1rvore a partir da raiz, comparando o valor key com a chave de cada n\u00f3: se key for menor que a chave do n\u00f3 atual, v\u00e1 para o filho esquerdo; se for maior, v\u00e1 para o direito; se as chaves forem iguais, o n\u00f3 buscado foi encontrado! O c\u00f3digo correspondente:<\/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 se torna igual a null, significa que a busca alcan\u00e7ou o final da \u00e1rvore (em termos conceituais, voc\u00ea est\u00e1 em um lugar inexistente da \u00e1rvore \u2014 o filho de uma folha).<\/p>\n<p>Vamos considerar a efici\u00eancia do algoritmo de busca em uma \u00e1rvore balanceada (uma \u00e1rvore onde os n\u00f3s est\u00e3o distribu\u00eddos mais ou menos uniformemente). Nesse caso, a efici\u00eancia da busca ser\u00e1 O(log(n)), sendo o logaritmo de base 2. Veja: se em uma \u00e1rvore balanceada h\u00e1 n elementos, isso significa que haver\u00e1 log(n) de base 2 n\u00edveis na \u00e1rvore. E, em cada itera\u00e7\u00e3o de busca, voc\u00ea desce um n\u00edvel.<\/p>\n<h3>Inser\u00e7\u00e3o<\/h3>\n<p>\nSe voc\u00ea entendeu a ess\u00eancia da busca, entender a inser\u00e7\u00e3o n\u00e3o ser\u00e1 dif\u00edcil. Voc\u00ea s\u00f3 precisa descer at\u00e9 a folha da \u00e1rvore (de acordo com as regras de descida descritas na busca) e se tornar seu descendente \u2014 \u00e0 esquerda ou \u00e0 direita, dependendo da chave. Implementa\u00e7\u00e3o:<\/p>\n<pre><code class=\"java\">   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<\/code><\/pre>\n<p>\nNeste caso, \u00e9 necess\u00e1rio armazenar, al\u00e9m do n\u00f3 atual, informa\u00e7\u00f5es sobre o pai do n\u00f3 atual. Quando current se tornar igual a null, a vari\u00e1vel parent conter\u00e1 a folha que precisamos. <br \/>\nA efici\u00eancia da inser\u00e7\u00e3o ser\u00e1, evidentemente, a mesma que a da busca \u2014 O(log(n)).<\/p>\n<h3>Remo\u00e7\u00e3o<\/h3>\n<p>\nA remo\u00e7\u00e3o \u00e9 a opera\u00e7\u00e3o mais complexa que teremos que realizar com a \u00e1rvore. \u00c9 evidente que, primeiro, precisamos encontrar o elemento que vamos remover. Mas e depois? Se simplesmente atribu\u00edmos o valor null \u00e0 sua refer\u00eancia, perderemos a informa\u00e7\u00e3o sobre a sub\u00e1rvore cujas ra\u00edzes s\u00e3o esse n\u00f3. Os m\u00e9todos de remo\u00e7\u00e3o da \u00e1rvore s\u00e3o divididos em tr\u00eas casos.<\/p>\n<h4>Primeiro caso. O n\u00f3 removido n\u00e3o tem filhos.<\/h4>\n<p>\nSe o n\u00f3 removido n\u00e3o tem filhos, isso significa que ele \u00e9 uma folha. Portanto, podemos simplesmente atribuir o valor null aos campos leftChild ou rightChild do seu pai. <\/p>\n<h4>Segundo caso. O n\u00f3 removido tem um filho.<\/h4>\n<p>\nEste caso tamb\u00e9m n\u00e3o \u00e9 muito complicado. Vamos voltar ao nosso exemplo. Suponha que precisemos remover o elemento com a chave 14. Concordem que, como ele \u00e9 o filho direito do n\u00f3 com a chave 10, qualquer um de seus filhos (neste caso, o direito) ter\u00e1 uma chave maior que 10, portanto podemos facilmente 'cortar' isso da \u00e1rvore e conectar o pai diretamente ao filho do n\u00f3 removido, ou seja, o n\u00f3 com a chave 10 se conecta ao n\u00f3 13. A situa\u00e7\u00e3o seria an\u00e1loga se precis\u00e1ssemos remover um n\u00f3 que \u00e9 o filho esquerdo de seu pai. Pensem a respeito \u2014 \u00e9 uma analogia exata. <\/p>\n<h4>Terceiro caso. O n\u00f3 tem dois filhos.<\/h4>\n<p>\nO caso mais complexo. Vamos analisar com um novo exemplo.<\/p>\n<p><img decoding=\"async\" alt=\"\u00c1rvore Bin\u00e1ria ou como preparar uma \u00e1rvore bin\u00e1ria de busca\" src=\"\/wp-content\/uploads\/2019\/03\/0d600478e4a046ae6f7267be49b231bc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h4>Busca do sucessor.<\/h4>\n<p>\n Suponha que precisamos remover o n\u00f3 com a chave 25. Quem colocaremos em seu lugar? Algu\u00e9m de seus sucessores (descendentes ou descendentes de descendentes) deve se tornar <i>o sucessor<\/i>(aquele que ocupar\u00e1 o lugar do n\u00f3 removido). <\/p>\n<p>Como entender quem deve se tornar o sucessor? \u00c9 intuitivamente claro que \u00e9 um n\u00f3 na \u00e1rvore cuja chave \u00e9 o pr\u00f3ximo maior em rela\u00e7\u00e3o ao n\u00f3 removido. O algoritmo consiste no seguinte. Devemos ir para o seu filho direito (sempre para a direita, pois j\u00e1 foi mencionado que a chave do sucessor \u00e9 maior que a chave do n\u00f3 removido), e ent\u00e3o percorrer a cadeia de filhos esquerdos desse filho direito. No exemplo, devemos ir para o n\u00f3 com a chave 35 e depois descer at\u00e9 a folha ao longo da cadeia de seus filhos esquerdos \u2014 neste caso, essa cadeia consiste apenas no n\u00f3 com a chave 30. Estritamente falando, estamos buscando o menor n\u00f3 em um conjunto de n\u00f3s que s\u00e3o maiores que o n\u00f3 procurado.<\/p>\n<p><img decoding=\"async\" alt=\"\u00c1rvore Bin\u00e1ria ou como preparar uma \u00e1rvore bin\u00e1ria de busca\" src=\"\/wp-content\/uploads\/2019\/03\/50c4e3e49111eec9e1fd13083ee9b9b0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nC\u00f3digo do m\u00e9todo para encontrar o sucessor:<\/p>\n<pre><code class=\"java\">    public Node&lt;T&gt; getSuccessor(Node&lt;T&gt; deleteNode) {\n        Node&lt;T&gt; parentSuccessor = deleteNode; \/\/ pai do sucessor\n        Node&lt;T&gt; successor = deleteNode; \/\/ sucessor\n        Node&lt;T&gt; current = successor.getRightChild(); \/\/ n\u00f3 'caminhante'\n        while (current != null) {\n            parentSuccessor = successor;\n            successor = current;\n            current = current.getLeftChild();\n        }\n        \/\/ ao sair do loop temos o sucessor e o pai do sucessor\n        if (successor != deleteNode.getRightChild()) { \/\/ se o sucessor n\u00e3o for igual ao filho direito do n\u00f3 removido\n            parentSuccessor.setLeftChild(successor.getRightChild()); \/\/ ent\u00e3o seu pai assume o filho do sucessor para n\u00e3o perd\u00ea-lo\n            successor.setRightChild(deleteNode.getRightChild()); \/\/ conectamos o sucessor ao filho direito do n\u00f3 removido\n        }\n        return successor;\n    }\n<\/code><\/pre>\n<p>\nC\u00f3digo completo do m\u00e9todo delete:<\/p>\n<pre><code class=\"java\">public boolean delete(int deleteKey) {\n        Node current = root;\n        Node parent = current;\n        boolean isLeftChild = false; \/\/ Dependendo se o n\u00f3 a ser removido \u00e9 um filho esquerdo ou direito de seu pai, a vari\u00e1vel booleana isLeftChild ser\u00e1 true ou false, respectivamente.\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) { \/\/ primeiro 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) { \/\/ segundo 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 { \/\/ terceiro 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>\nA complexidade pode ser aproximada a O(log(n)).<\/p>\n<h3>Busca pelo m\u00e1ximo\/m\u00ednimo na \u00e1rvore<\/h3>\n<p>\n\u00c9 evidente como encontrar o valor m\u00ednimo\/m\u00e1ximo na \u00e1rvore \u2014 deve-se passar sequencialmente pela cadeia de elementos \u00e0 esquerda\/direita da \u00e1rvore, respectivamente; ao chegar a uma folha, ela ser\u00e1 o elemento m\u00ednimo\/m\u00e1ximo.<\/p>\n<pre><code class=\"java\">    public Node getMinimum(Node startPoint) {\n        Node current = startPoint;\n        Node parent = current;\n        while (current != null) {\n            parent = current;\n            current = current.getLeftChild();\n        }\n        return parent;\n    }\n\n    public Node getMaximum(Node startPoint) {\n        Node current = startPoint;\n        Node parent = current;\n        while (current != null) {\n            parent = current;\n            current = current.getRightChild();\n        }\n        return parent;\n    }\n<\/code><\/pre>\n<p>\nA complexidade \u00e9 O(log(n))<\/p>\n<h3>Percurso sim\u00e9trico<\/h3>\n<p>\nO percurso \u00e9 a visita a cada n\u00f3 da \u00e1rvore com o objetivo de realizar alguma a\u00e7\u00e3o com ele.<\/p>\n<p>Algoritmo de percurso sim\u00e9trico recursivo:<\/p>\n<ol>\n<li>Realizar a\u00e7\u00e3o com o filho esquerdo<\/li>\n<li>Realizar a\u00e7\u00e3o com si mesmo<\/li>\n<li>Realizar a\u00e7\u00e3o com o filho direito<\/li>\n<\/ol>\n<p>\nC\u00f3digo:<\/p>\n<pre><code class=\"java\">    public void inOrder(Node current) {\n        if (current != null) {\n            inOrder(current.getLeftChild());\n            System.out.println(current.getData() + \" \");\/\/Aqui pode haver qualquer coisa\n            inOrder(current.getRightChild());\n        }\n    }\n<\/code><\/pre>\n<p><\/p>\n<h2>Conclus\u00e3o<\/h2>\n<p>\nFinalmente! Se eu deixei algo sem explica\u00e7\u00e3o ou se h\u00e1 alguma observa\u00e7\u00e3o, fico aguardando nos coment\u00e1rios. Como prometido, trago o c\u00f3digo completo.<\/p>\n<p>Node.java:<\/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\n    public void setLeftChild(Node newNode) {\n        leftChild = newNode;\n    }\n\n    public void setRightChild(Node newNode) {\n        rightChild = newNode;\n    }\n\n    public Node getLeftChild() {\n        return leftChild;\n    }\n\n    public Node 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>Degenera\u00e7\u00e3o para O(n)<\/h3>\n<p>\nMuitos de voc\u00eas podem ter notado: e se fizermos com que a \u00e1rvore se tornasse desbalanceada? Por exemplo, ao inserir n\u00f3s com chaves crescentes: 1,2,3,4,5,6... A \u00e1rvore acabaria se parecendo com uma lista encadeada. E sim, a \u00e1rvore perder\u00e1 sua estrutura arb\u00f3rea, e, portanto, a efici\u00eancia no acesso aos dados. A complexidade das opera\u00e7\u00f5es de busca, inser\u00e7\u00e3o e exclus\u00e3o se tornar\u00e1 a mesma que a de uma lista encadeada: O(n). Essa \u00e9 uma das principais desvantagens das \u00e1rvores bin\u00e1rias, na minha opini\u00e3o.<\/p>\n<p class=\"for_users_only_msg\">Apenas usu\u00e1rios registrados podem participar da pesquisa. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Entre<\/a><\/noindex>, por favor.<\/p>\n<h2 class=\"default-block__polling-title\">Eu n\u00e3o estou no Habr h\u00e1 tanto tempo, e gostaria de saber sobre quais temas voc\u00eas gostariam de ver mais artigos?<\/h2>\n<ul class=\"content-list content-list_polling\">\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Estruturas de dados<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Algoritmos (DP, recurs\u00e3o, compress\u00e3o de dados, etc.)<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Aplica\u00e7\u00f5es de estruturas de dados e algoritmos na vida real<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Programa\u00e7\u00e3o de aplicativos Android em Java<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Programa\u00e7\u00e3o de aplicativos web em Java<\/p>\n<\/li>\n<\/ul>\n<p>    Votaram 2 usu\u00e1rios. 1 usu\u00e1rio se absteve.<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.3 - 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.\" \/>\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\/pt\/blog\/administrirovanie\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\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.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/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 ou como preparar uma \u00e1rvore bin\u00e1ria de busca | ProHoster","description":"Prel\u00fadio Este artigo \u00e9 dedicado \u00e0s \u00e1rvores bin\u00e1rias de busca.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/binary-tree-ili-kak-prigotovit-binarnoe-derevo-poiska","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","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.","og:url":"https:\/\/prohoster.info\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/30530","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=30530"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/30530\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/22528"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=30530"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=30530"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=30530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}