E N D
Árvores de Busca • Uma árvore que suporta eficientes operações de busca, inclusão e exclusão é chamada de árvore de busca. A árvore é usada para armazenar um conjunto finito de chaves obtidas de um conjunto totalmente ordenado de chaves K. Cada nó da árvore contém um ou mais chaves e todas as chaves na árvore são únicas, sem duplicação. • A diferença entre uma árvore comum e uma árvore de busca é que, nesta última, as chaves não aparecem em nós arbitrários. Existe um critério de ordenação de dados que determina aonde cada chave pode figurar na árvore em relação às demais. • Serão apresentadas as árvores de busca: • de M caminhos (M-Way) • binárias.
Binary Search Tree (BST) • Definição (Árvore de busca M-way) Uma árvore de buscaM-wayT é um conjunto finito de chaves. Ou o conjunto é vazio, T = ; ou o conjunto é constituído de n sub árvores M-way T1 , T2 ,..., Tn-1, e n-1 chaves, k1 , k2 ,..., kn-1, T = {T0,k1, T1, k2, ..., kn-1, Tn-1} aonde 2 n M, tal que as chaves e os nós satisfaçam às seguintes propriedades de ordenação de dados: • As chaves em cada nó são distintas e ordenadas, i.e., ki<ki+1 para 1 i n-1 • Todas as chaves contidas na sub árvore Ti-1 são menores do que ki. A árvore Ti-1 é chamada sub árvore da esquerda com respeito à chave ki. • Todas as chaves contidas na sub árvore Ti são maiores do que ki. A árvore Ti+1 é chamada sub árvore da direita com respeito à chave ki.
Binary Search Tree (BST) • Definição (Árvore Binária de Busca) A Árvore Binária de Busca T é um conjunto finito de chaves. Ou o conjunto é vazio, T = ; ou o conjunto consiste da raiz r e exatamente duas Árvores Binárias de Busca TL e TR , T={r,TL,TR}, tais que as seguintes propriedades sejam satisfeitas: • Todas as chaves contidas na sub árvore da esquerda, TL, são menores do que r. • Todas as chaves contidas na sub árvore da direita, TR , são maiores do que r.
Busca em Árvores de Busca M-Way • Busca do objeto x inicia na raiz • Se a raiz estiver vazia a busca falha • As chaves contidas na raiz são examinadas para verificar se o objeto buscado está presente • Se o objeto não estiver presente três casos podem ocorrer: • Objeto buscado é menor do que k1 • a busca prossegue em T0; • Objeto buscado é maior do que kn-1 • a busca prossegue em Tn-1; • Existe um i tal que ki < x < ki+1 • a busca prossegue em Ti
Busca em Árvores Binárias de Busca • Semelhante à busca em árvores de busca M-Way • Apenas cada nó só possui um objeto e duas sub árvores
Árvore Binária Perfeita • Definição (Árvore Binária Perfeita) A Árvore Binária Perfeita de altura h 0 é um árvore binária T={r,TL,TR} com as propriedades: • Se h=0, então TL = e TR = . • Caso contrário, h>0, caso no qual ambos TL e TR são Árvores Binárias Perfeitas de altura h -1.
Interface SearchTree // pgm10_01.java public interface SearchTree extends Tree, SearchableContainer { Comparable findMin (); Comparable findMax (); }
Classe BinarySearchTree // pgm10_02.java public class BinarySearchTree extends BinaryTree implements SearchTree { // ... }
Classe Association public class Association extends AbstractObject { protected Comparable key; protected Object value; // ... } // só aparece por causa de getKey
Métodos da Classe Association public class Association extends AbstractObject { protected Comparable key; protected Object value; public Association (Comparable key, Object value) { this.key = key; this.value = value; } public Association (Comparable key) { this (key, null); } public Comparable getKey () { return key; } public Object getValue () { return value; } // ... }
Métodos da Classe BinarySearchTree • getLeftBST • getRightBST • find • findMin • insert • attachKey • balance • withdraw
Métodos getLeftBST e getRightBST // pgm10_03.java public class BinarySearchTree extends BinaryTree implements SearchTree { private BinarySearchTree getLeftBST() { return (BinarySearchTree) getLeft(); } private BinarySearchTree getRightBST() { return (BinarySearchTree) getRight(); } // ... }
Método find // pgm10_04.java public class BinarySearchTree extends BinaryTree implements SearchTree { public Comparable find (Comparable object) { if(isEmpty()) return null; int diff = object.compare((Comparable) getKey()); if(diff == 0) return (Comparable) getKey(); else if(diff < 0) return getLeftBST().find(object); else return getRightBST().find(object); } }
Método findMin public Comparable findMin () { if(isEmpty()) return null; else if(getLeftBST().isEmpty()) return (Comparable) getKey(); else return getLeftBST().findMin(); } // ...
Inserção de itens em BST • A inclusão de nós em árvores de busca deve ser precedida de uma operação de busca. Esta operação indica se o nó buscado já existe na árvore e, em caso de não existência, o local aonde deve ser feita a inclusão. Convém lembrar que uma busca sempre termina em folha e os nós a incluir serão incluídos como filhos da folha aonde se encerrou a busca.
Método insert (1) // pgm10_05.java public class BinarySearchTree extends BinaryTree implements SearchTree { public void insert (Comparable object) { if(isEmpty()) attachKey (object);
Método insert (2) else { int diff = object.compare((Comparable) getKey()); if(diff == 0) throw new IllegalArgumentException( “chave duplicada"); if(diff < 0) getLeftBST().insert(object); else getRightBST().insert(object); } balance(); } }
Métodos attachKey e balance public void attachKey (Object object) { if(!isEmpty()) throw new InvalidOperationException(); key = object; left = new BinarySearchTree(); right = new BinarySearchTree(); } protected void balance() {}
Remoção de itens em BST • A exclusão de nós em árvores de busca pode configurar um de 3 casos. • Se o nó não tiver filhos pode ser excluído sem exigir ajustamento da árvore. • Se o nó a excluir tiver apenas uma sub árvore, este nó pode ser excluído e deve ser substituído por seu filho único. • Se o nó a excluir tiver mais de um filho, para que ele possa ser excluído, deve ser substituído por seu antecessor ou seu sucessor em ordem infixa. O nó substituto deve ser excluído da sua posição gerando outro processo de exclusão. • Considerando o caso do sucessor em ordem infixa, o nó a ser excluído deve ser substituído pelo nó obtido alcançando-se o nó mais à esquerda da sub árvore direita do nó a excluir.
Remoção de itens em BST • Remoção do nó (4) folha em BST • Remoção do nó (1) não folha em BST
Método withdraw (1) // pgm10_06.java public class BinarySearchTree extends BinaryTree implements SearchTree { public void withdraw (Comparable object) { if(isEmpty()) throw new IllegalArgumentException( "objeto não encontrado"); int diff = object.compare ((Comparable) getKey()); if(diff == 0) { if(!getLeftBST().isEmpty()) { Comparable max = getLeftBST().findMax(); key = max; getLeftBST().withdraw(max); }
Método withdraw (2) else if(!getRightBST().isEmpty()) { Comparable min = getRightBST().findMin(); key = min; getRightBST().withdraw(min); } else detachKey(); } else if(diff < 0) getLeftBST().withdraw(object); else getRightBST().withdraw(object); balance(); } // ... }
Conceito de AVL Adelson-Velskii e Landis propuseram as condições de balanceamento para uma árvore binária que recebeu como sigla suas iniciais. Definição (Condição de equilíbrio AVL) Uma árvore binária vazia é AVL balanceada . Uma árvore binária não-vazia, T={r,TL,TR} , é AVL balanceada se tanto TL quanto TR forem AVL balanceadas e |hL-hR|<=1 aonde hL é a altura of TL e hR é a altura of TR .
Classe AVLTree // pgm10_07.java public class AVLTree extends BinarySearchTree { protected int Height; // ... }
Construtor // pgm10_08.java public class AVLTree extends BinarySearchTree { protected int Height; public AVLTree() { Height = -1; } // ... }
Métodos getHeight, adjustHeight e getBalanceFactor public int getHeight () { return Height; } protected void adjustHeight() { if(isEmpty()) Height = -1; else Height = 1 + Math.max(left.getHeight(), right.getHeight()); } protected int getBalanceFactor() { if(isEmpty()) return 0; else return left.getHeight() - right.getHeight(); }
Inserção de itens em Árvores AVL • 1o. Passo – Inserir o item • 2o. Passo – Balancear a árvore
Balanceamento de Árvores AVL • O balanceamento de árvores AVL é feito por operações chamadas de rotações, que podem ser: • Rotações simples (LL e RR) • Rotações duplas (LR e RL)
Rotações simples • A rotação LL ocorre quando um nó (B) tem a sub árvore da esquerda maior do que a da direita e seu filho da esquerda (A) tem sub árvore da esquerda maior do que a da direita • A rotação RR ocorre quando um nó (B) tem a sub árvore da direita maior do que a da esquerda e seu filho da direita (A) tem sub árvore da direita maior do que a da esquerda
Rotações duplas • A rotação LR ocorre quando um nó (C) tem a sub árvore da esquerda maior do que a da direita e seu filho da esquerda (A) tem sub árvore da direita maior do que a da esquerda. Aplica-se uma rotação RR a A seguida de uma rotação LL aplicada a C. • A rotação RL ocorre quando um nó (C) tem a sub árvore da direita maior do que a da esquerda e seu filho da direita (A) tem sub árvore da esquerda maior do que a da direita. Aplica-se uma rotação LL a A seguida de uma rotação RR aplicada a C.
Propriedades das rotações simples • Existem três propriedades importantes da rotação LL: • A rotação não destrói a propriedade de ordenação de dados e, portanto, o resultado ainda é uma árvore de busca. A sub árvore AL permanece entre os nós A e B, e a sub árvore BR fica à direita do nó B. • Após a rotação tanto A quanto B são AVL balanceadas. Os nós A e B ficam com fator de balanceamento igual a zero. • Após a rotação a árvore permanece com a altura original. A inclusão do item não aumenta a altura da árvore.
Balanceamento de árvores AVL • Os desbalanceamentos e as rotações de equilíbrio correspondentes podem ser enquadrados em seis categorias, ou casos, adiante descritos. O ancestral mais novo, desbalanceado, do novo nó inserido é ya. Seu filho na direção do desbalanceamento é s. Os sufixos l e r representam filho mais velho e filho mais novo, respectivamente:
Categorias de rotações • 1o caso: O novo nó é incluído na sub árvore esquerda da sub árvore esquerda do nó ya. Este caso tem solução chamada de rightrotation ou rotação LL • 2o caso: O novo nó é incluído na sub árvore direita da sub árvore direita do nó ya. Este caso tem solução chamada de leftrotation ou rotação RR • 3 o caso: O novo é incluído na sub árvore esquerda da sub árvore direita do filho mais velho de ya (rotação LR) • 4 o caso: O novo nó é incluído na sub árvore direita da sub árvore direita do filho mais velho de ya (LR) • 5 o caso: O novo nó é incluído na sub árvore direita da sub árvore esquerda do filho mais novo de ya (RL) • 6 o caso: O novo nó incluído na sub árvore esquerda da sub árvore esquerda do filho mais novo de ya(RL)