Programação II Conhecida também como: Árvore binária ordenada Árvore binária de busca Aresenta relação de ordem entre os nodos Ordem definida através do camo chamado chave CHAVE Prof. Mateus Raeder Chaves dulicadas não são ermitidas Cada nó ossui uma chave única na árvore! Universidade do Vale do Rio dos Sinos - São Leooldo - Não há chaves dulicadas!!! FILHO DA ESQUERDA FILHO DA DIREITA Crie árvores inserindo os seguintes nós (em ordem): a), 22, 10,,, 15, 0, 22 b) j, x, o, m, z, a, j, h, i Valor da chave MENOR que a chave do ai Raiz Valor da chave MAIOR que a chave do ai a) b) j 22 a x 10 1 10 h o z 0 15 i m Classe Nodo Binário ublic class BSTNode { rotected int key; rotected BSTNode left, right; ublic BSTNode() { left = right = null; ublic BSTNode(int num) { this(num,null,null); ublic BSTNode(int num, BSTNode lt, BSTNode rt) { this.key = num; left = lt; right = rt; ublic int getkey() { return key; ublic void setkey(int key) { this.key = key; Classe Nodo Binário ublic BSTNode getleft() { return left; ublic void setleft(bstnode left) { this.left = left; ublic BSTNode getright() { return right; ublic void setright(bstnode right) { this.right = right; 1
Classe Árvore Binária de Pesquisa ublic class BST { rivate BSTNode root = null; ublic BST() { ublic void clear() { root = null; ublic boolean isemty() { return root == null; ublic BSTNode getrootnode (){ return root; Busca de valor A rocura de um valor em uma árvore binária é mais ráida do que em listas ou vetores. Como funciona: Para cada nó, comare a chave a ser localizada com o valor armazenado no nó correntemente aontado Se a chave for menor, vá ara a sub-árvore esquerda, e tente novamente Senão vá ara a sub-árvore direita, e tente novamente A busca ara quando: For encontrado o nó Ou quando não há mais meios de continuar, ois a chave não está na árvore ublic BSTNode search (int el) { Busca de valor rivate BSTNode search (BSTNode, int el) { while (!= null) { se valor rocurado == chave do nó, retorna referência ao nó if (el==.key) return ; se valor rocurado < chave do nó, rocurar na sub-árvore esquerda deste nó else if (el<.key) =.left; se valor rocurado > chave do nó, rocurar na sub-árvore direita deste nó else =.right; caso chave não foi achada, retorna null Exemlo de busca de valor ublic BSTNode search (int el) { rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 Exemlo de busca de valor Exemlo de busca de valor ublic BSTNode search (int el) { ublic BSTNode search (int el) { rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 2
Exemlo de busca de valor Exemlo de busca de valor ublic BSTNode search (int el) { ublic BSTNode search (int el) { rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 Exemlo de busca de valor Exemlo de busca de valor ublic BSTNode search (int el) { ublic BSTNode search (int el) { rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 Exemlo de busca de valor Exemlo de busca de valor ublic BSTNode search (int el) { ublic BSTNode search (int el) { rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 3
Exemlo de busca de valor Exemlo de busca de valor ublic BSTNode search (int el) { ublic BSTNode search (int el) { rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 Exemlo de busca de valor Exemlo de busca de valor ublic BSTNode search (int el) { ublic BSTNode search (int el) { rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 Exemlo de busca de valor ublic BSTNode search (int el) { rivate BSTNode search (BSTNode, int el) { while (!= null) { if (el==.key) return ; else if (el<.key) =.left; else =.right; 10 1 Inserindo uma nova chave ublic boolean insert (int el) { BSTNode = root, rev = null; caso o valor já exista na árvore, não inserir e retornar false rocurando um lugar ara colocar o novo nó while (!= null) { rev = ; if (el<.key) =.left; else =.right; se árvore vazia else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el);
Exemlo de inserção Exemlo de inserção ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = Exemlo de inserção Exemlo de inserção ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = Exemlo de inserção Exemlo de inserção ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); el = 23 5
Exemlo de inserção Exemlo de inserção ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = 23 ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = 23 Exemlo de inserção Exemlo de inserção ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = 23 ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = 23 Exemlo de inserção Exemlo de inserção ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = 23 ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = 23 6
Exemlo de inserção Exemlo de inserção ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = 23 ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); rev el = 23 Exemlo de inserção Exemlo de inserção ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); el = 23 rev 23 ublic boolean insert (int el) { BSTNode = root, rev = null; while (!= null) { rev = ; if (el<.key) =.left; else =.right; else if (rev.key<el) rev.right = new BSTNode(el); else rev.left = new BSTNode(el); el = 23 rev 23 É o rocesso de visitar cada nó da árvore exatamente uma vez. Visitar: Fazer algo com o nó como exibi-lo, gravá-lo, etc. O ercurso ode ser interretado como colocar todos os nós em uma linha ou a linearização da árvore. Os ercursos odem ser em extensão ou em rofundidade. Percursos em extensão: visitam todos os nós de cada nível, nível or nível (indo do mais alto ao mais baixo, ou vice-versa). Percursos em rofundidade: ercorre os caminhos das árvores. Percorre rimeiramente todo o caminho mais a esquerda, e assim or diante. - ercorre a sub-árvore direita. ré-fixada ós-fixada 7
ré-fixada ré-fixada ré-fixada ré-fixada ré-fixada ré-fixada 3 3
ré-fixada ré-fixada ré-fixada ré-fixada ré-fixada ré-fixada 6 - Percorre 3 esquerda 7 9
ré-fixada ré-fixada 6 6 ré-fixada ré-fixada ré-fixada ré-fixada ré-ordem: 10
ós-fixada ós-fixada ós-fixada ós-fixada 3 3 ós-fixada ós-fixada 3 3 11
ós-fixada ós-fixada ós-fixada ós-fixada ós-fixada ós-fixada 6 - Percorre 3 direita 7 - Percorre 3 direita 7
ós-fixada ós-fixada 6 6 ós-fixada ós-fixada ós-fixada ós-fixada 13
ós-fixada ós-fixada ós-ordem: - ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 - ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 3 1
- ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 3 - ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 7 3 7 - ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 7 3 7 15
- ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 7 3 7 - ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 7 6 3 7 6 - Visita 3 o nó 7 - Visita 3 o nó 7 - ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 7 6 3 7 6 16
- ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 7 6 3 7 6 10 - ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 7 6 10 3 7 6 10 - ercorre a sub-árvore direita. - ercorre a sub-árvore direita. 3 7 6 10 in-ordem: 3 7 6 10 17
Percorra cada uma das árvores abaixo em PÓS-, PRÉ- e IN-ORDEM: a) b) c) 30 50 7 10 30 Resostas: a) PÓS-ORDEM: 30 - - 50-6 - 65-70 - - PRÉ-ORDEM: - - 30 - - 50-70 - 65-6 IN-ORDEM: - 30 - - 50 - - 65-6 - 70 b) PÓS-ORDEM: 5-52 - 5-50 - 7 - - PRÉ-ORDEM: - - 50-5 - 5-52 - 7 IN-ORDEM: - 5-50 - 52-5 - - 7 65 5 5 17 c) PÓS-ORDEM: 5-9 - - 13-17 - 10-30 - - PRÉ-ORDEM: - - 10 - - 5-9 - 17-13 - 30 IN-ORDEM: 5 - - 9-10 - 13-17 - - 30-6 52 5 9 13 PRÉ-ORDEM - ercorre esquerda; - ercorre direita; PÓS-ORDEM IN-ORDEM PRÉ-ORDEM PÓS-ORDEM IN-ORDEM - ercorre esquerda; - ercorre esquerda; - ercorre esquerda; - ercorre esquerda; - ercorre direita; - ercorre esquerda; - ercorre direita; - visita Programação o nó; II Prof. Mateus - ercorre Raeder direita. - ercorre direita; - visita Programação o nó; II Prof. Mateus - ercorre Raeder direita. IN-ORDEM PRÉ-ORDEM ublic void inorder() { inorder(root); ublic void reorder() { reorder(root); IN-ORDEM - ercorre esquerda; - ercorre direita. rivate void inorder (BSTNode ) { if (!= null) { inorder(.left); System.out.rint(.key " "); inorder(.right); PRÉ-ORDEM - ercorre esquerda; - ercorre direita; rivate void reorder(bstnode ) { if (!= null) { System.out.rint(.key " "); reorder(.left); reorder(.right); PÓS-ORDEM ublic void ostorder() { ostorder(root); Remoção de um nó Ao remover um nó, 3 situações odem ocorrer : Situação 1: Exclusão de uma folha O nó é uma folha e não tem filhos o onteiro do seu ai é ajustado ara nulo. PÓS-ORDEM - ercorre esquerda; - ercorre direita; rivate void ostorder(bstnode ) { if (!= null) { ostorder(.left); ostorder(.right); System.out.rint(.key " "); Nodo a ser excluído 10 30 30 1
Remoção de um nó Ao remover um nó, 3 situações odem ocorrer : Situação 2: Nodo tem um filho Ponteiro do ai aonta ara o filho deste nodo Remoção de um nó Ao remover um nó, 3 situações odem ocorrer : Situação 3: Nodo tem dois filhos Dois tios de remoção Por cóia Por fusão Nodo a ser excluído Nodo a ser excluído 30 30 10 30 Remoção or cóia Remoção or cóia Remove uma chave X (chave do nó que se quer remover): sobrescrevendo-a or uma outra chave Y Y é o maior valor na sub-árvore esquerda, ois este vai ser maior que todos os valores da sub-árvore esquerda e ao mesmo temo menor que os valores da sub-árvore direita e então removendo o nó que contem Y que será um dos casos simles: folha, ou nó com aenas um filho 1 10 30 2 10 30 Coia 55 55 52 52 56 Maior valor da sub-árvore esquerda 56 3 10 30 Remoção or cóia 55 52 Final 55 52 56 Deleta nodo (situação 1 ou 2) 56 Encontra o ai de um nodo rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; 19
Exemlo de encontro de ai Exemlo de encontro de ai rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev Exemlo de encontro de ai Exemlo de encontro de ai rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev Exemlo de encontro de ai Exemlo de encontro de ai rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev;? Sim rev rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev
Exemlo de encontro de ai Exemlo de encontro de ai rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev Exemlo de encontro de ai Exemlo de encontro de ai rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev;? Não rev Exemlo de encontro de ai Exemlo de encontro de ai rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev 21
Exemlo de encontro de ai Exemlo de encontro de ai rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; rev Exemlo de encontro de ai rotected BSTNode searchfather (int el) { BSTNode = root; BSTNode rev = null; acha o nó com a chave el while (!= null &&!(.key==el)) { rev = ; if (.key < el) =.right; else =.left; if (!=null &&.key==el) return rev; 10 30 rev Remoção or cóia ublic void deletebycoying (int el) { BSTNode node, father = null; node = search (el) ; rocura nó a ser deletado if (node!= null && node.key==el) { if (node!=root) father = searchfather (el); rocura ai do nó a ser deletado if (node.right == null){ nó não tem filho direito (situação 2 ou situação 1); if (node==root) root= node.left; else if (father.left == node) father.left = node.left; else father.right = node.left; else if (node.left == null) { nó não tem filho esquerdo (caso 2) if (node==root) root= node.right; else if (father.left == node) father.left = node.right; else father.right = node.right; else { nó tem ambos os filhos: fazer remoção or cóia BSTNode tm = node.left; 1. egando sub-arvore esquerda while (tm.right!= null) 2. acha a osição mais a direita da sub-árvore esquerda do nó tm = tm.right; deletebycoying (tm.key); remove or coia o nó que ossui o maior valor da sub-arvore esquerda do nó a ser deletado node.key = tm.key; coia valor da chave do maior nó da sub-árvore esquerda else if (root!= null) System.out.rintln("el " el " is not in the tree"); else System.out.rintln("the tree is emty"); Exemlo de remoção or cóia ublic void deletebycoying (int el) { BSTNode node, father = null; node = search (el) ; if (node!= null && node.key==el) { if (node!=root) father = searchfather (el); if (node.right == null){ if (node==root) root= node.left; else if (father.left == node) father.left = node.left; else father.right = node.left; else if (node.left == null) { if (node==root) root= node.right; else if (father.left == node) father.left = node.right; else father.right = node.right; else { BSTNode tm = node.left; while (tm.right!= null) tm = tm.right; deletebycoying (tm.key); node.key = tm.key; 10 30 else if (root!= null) System.out.rintln("el " el " is not in the tree"); else System.out.rintln("the tree is emty"); 55 52 Remoção or fusão A solução consiste em fusionar as duas sub-árvores do nó a ser deletado em uma. Como na organização da árvore binária, todos os valores da sub-árvore a esquerda são menores que os valores da sub-árvore a direita Deve-se encontrar o maior valor na sub-árvore esquerda (o mais na direita) Este maior nó assa a ser ai da sub-árvore direita do nó a ser removido Remove a chave, removendo o nó que contém a chave E o ai do nó removido assa a aontar ara a nova subárvore 56 22
1 Remoção or fusão 2 3 Remoção or fusão Final 50 10 30 10 30 10 30 50 10 30 55 55 55 Passa a ser ai 55 52 52 52 52 56 70 56 Maior valor da sub-árvore esquerda 56 56 70 Remoção or fusão ublic void deletebymerging (int el) { BSTNode tm, node,father = null; node = search (el) ; rocura nó a ser deletado if (node!= null && node.key==el) { if (node!=root) father = searchfather (el); rocura ai do nó a ser removido if (node.right == null){ nó não tem filho direito (situações 1 e 2); if (root==node) root=node.left; else if (father.left == node) father.left = node.left; else father.right = node.left; else if (node.left == null) { nó não tem filho esquerdo (situação 2) if (root==node) root=node.right; else if (father.left == node) father.left = node.right; else father.right = node.right; Exemlo de remoção or fusão ublic void deletebymerging (int el) { BSTNode tm, node,father = null; node = search (el) ; if (node!= null && node.key==el) { if (node!=root) father = searchfather (el); if (node.right == null){ if (root==node) root=node.left; else if (father.left == node) father.left = node.left; else father.right = node.left; else if (node.left == null) { if (root==node) root=node.right; else if (father.left == node) father.left = node.right; else father.right = node.right; else { se tem dois filhos, faz deleção or fusão else { tm = node.left; ega sub-arvore esquerda tm = node.left; while (tm.right!= null) tm = tm.right; ega filho mais a direita da sub-arvore esquerda while (tm.right!= null) tm = tm.right; 55 tm.right = node.right; filho a direita da sub-arvore esquerda assa a ter tm.right = node.right; como filho direito o filho direito do nó a ser deletado if (root==node) root = node.left; if (root==node) root = node.left; else if (father.left == node) father.left = node.left; else if (father.left == node) father.left = node.left; else father.right = node.left; else father.right = node.left; 52 else if (root!= null) System.out.rintln("el " el " is not in the tree"); else if (root!= null) System.out.rintln("el " el " is not in the tree"); else System.out.rintln("the tree is emty"); else System.out.rintln("the tree is emty"); 56 23