Árvores Binárias Profa. Patrícia A. Jaques Luiz Gonzaga Jr Contribuições Algumas...
Transcript of Árvores Binárias Profa. Patrícia A. Jaques Luiz Gonzaga Jr Contribuições Algumas...
Árvores Binárias
Profa. Patrícia A. Jaques
Luiz Gonzaga JrContribuições
Algumas transparências são da profa. Renata Galante da II/UFRGScom permissão
Nivelamento - PIPCA 2012/1 2
Árvore Binária
• É uma árvore onde cada nó pode conter nenhum, 1 ou 2 filhos apenas– Grau=2.
• Uma árvore binária é formada por nós onde cada nó contém um valor, um ponteiro esquerdo e um ponteiro direito.
A
D
CB
E F
G
Nivelamento - PIPCA 2012/1 3
Árvore Binária
• O nó A é a raiz da árvore. Como B é a raiz da sua sub-árvore esquerda dizemos que B é o filho esquerdo de A, do mesmo modo, C é o filho direito de A. Por isso A é o pai dos nós B e C e estes dois são irmãos.
A
D
CB
E F
G
filho esquerdo de A filho direito de A
Nivelamento - PIPCA 2012/1 4
EstritamenteBinária
Tipos de Árvores Binárias: Estritamente Binária
• Ocorre quando todo nó que não é folha tiver sub-arvores esquerda e direita não vazias.– todo nó tem 0 ou 2 filhos.
• Número de nós em uma árvore estritamente binária com n folhas:– 2n-1
bibliografia:Szwarcfiter, J. & Markenzon, Lilian. Estrturas de Dados e seus Algoritmos. Rio de Janeiro: LTC, 1994
Nivelamento - PIPCA 2012/1 5
Binária Completa
Tipos de Árvores Binárias: Binária Completa
• É uma árvore estritamente binária onde todos os nós folhas se encontram ou no último ou no penúltimo nível da árvore.
bibliografia:Szwarcfiter, J. & Markenzon, Lilian. Estrturas de Dados e seus Algoritmos. Rio de Janeiro: LTC, 1994
Nivelamento - PIPCA 2012/1 6
Binária Cheia
Tipos de Árvores Binárias: Binária Cheia
• Árvore estritamente binária onde os nós folhas se encontram no último nível.
• O número total de nós em (tn) em uma árvore binária cheia de altura h é:– tn=2h-1
• Assim, pela mesma fórmula podemos afirmar que, numa árvore binária completa, a altura h de uma árvore é dada por:– h= log2(tn+1)
• Embora a árvore binária completa possua muitos nós, a distância da raiz até qualquer folha (profundidade) é relativamente pequena.
bibliografia:Szwarcfiter, J. & Markenzon, Lilian. Estrturas de Dados e seus Algoritmos. Rio de Janeiro: LTC, 1994
Nivelamento - PIPCA 2012/1 7
A
CB
D GFE
Endereço da raiz
A
CB
GFED
Árvores Binárias: representação
chave do nó
referência para filho esquerdo referência
para filho direito
Nivelamento - PIPCA 2012/1 8
Aplicação de Árvores Binárias
• Representação de expressões aritméticas em árvores binárias– Dada uma expressão aritmética, sua representação
em árvore binária é feita de tal forma que a ordem de prioridade das operações fica implícita.
Regra:• O operador de menor prioridade aparece na
raiz;• A sub-expressão à esquerda desse operador
dá origem à sub-árvore esquerda;• A sub-expressão à direita do operador dá
origem à sub-árvore direita.
Nivelamento - PIPCA 2012/1 9
Representação de expressões aritméticas em árvores binárias
+
A *
CB
Ex: A + B * C
Obs. Operandos sempre aparecem como folhas; operadores, nunca.
Nivelamento - PIPCA 2012/1 10
Representação de expressões aritméticas em árvores binárias
• Caminhamentos: • Em pos-ordem Notação polonesa pós fixada.
– Ex: A B C * + (na primeira expressão);
• Em in-ordem Forma original (infixada) sem parênteses.– Ex: A + B * C (primeira expressão);
• Em pré-ordem Notação polonesa prefixada (sem grande utilidade).– Ex: + A * B C (primeira expressão);
• Obs. A notação polonesa pós fixada é muito útil (principalmente para as máquinas), pois exibe os operadores na ordem de execução das operações.
Nivelamento - PIPCA 2012/1 11
Algoritmo para gerar uma árvore binária a partir de uma expressão aritmética em notação infixa
Procedimento Interpretar(string)->ponteiroCOMEÇO 1. fazer uma árvore com a string como único nó; 2. procurar por operadores de MENOR precedência (+ ou -) que
não estejam dentro de “(“ e “)”, pois estes serão considerados um operando.se tem, substitua a árvore por uma com o operador no nó raiz e com
os operandos nos nós folha. (se você procurar o PRIMEIRO operando com menor precedência, basta dividir a árvore como explicado e aplicar esse procedimento de procurar operador de menor precedência recursivamente no nó da DIREITA). Lembre-se que um operando é um número, uma variável uma expressão entre parêntesis ou uma função.
3. repetir o procedimento 2 com operadores de MÉDIA precedência (* e /) SÓ EM NÓS FOLHA;
4. repetir o procedimento para operadores com MAIOR precedência (só o ^);
5. percorrer os nos folha (todos contém operandos) se o operando é número ou variável, não mexe. se o operando é expressão entre parêntesis, substituir esse nó por
Interpretar(expressão sem os parêntesis); FIM Interpretar.
Nivelamento - PIPCA 2012/1 12
Algoritmo para avaliar a árvore (calcular a expressão)
Algoritmo eval (BinaryTreeNode v) {/* recebe nó raiz como parâmetro: a classe BinaryTreeNode, alémdos ponteiros para filhos esquerdo e direito, também contémoutros dois atributos:
1) char operador;2) double operando;real retorno 0;if v == null { não tem árvore - devolve valor zero }then retorno 0;else if v.operador==’’ /* se operando é igual ‘’, então nóguarda operando*/then return v.operando; //devolve valor contido no nodoelse switch a.operador { //operador - executa operação
case “+”: retorno eval(v.left) + eval(v.right);case “-” : retorno eval(v.left) - eval(v.right);case “*” : retorno eval(v.left) * eval(v.right);case “/” : retorno eval(v.left) / eval(v.right);
}return retorno;
}
Nivelamento - PIPCA 2012/1 13
Árvore Binária de Pesquisa
• Também chamada de:– árvore binária de busca – ou árvore binária ordenada
• apresentam uma relação de ordem entre os nodos
• ordem é definida por um campo denominado chave
• não permite chaves duplicadas, ou seja, cada nó tem um valor de chave diferente
esq chave dir
Nivelamento - PIPCA 2012/1 14
Árvore Binária de Pesquisa
raiz500
300 800
150 400 900600
filho da esquerda:valor da chave menor que o valor da chave do nó pai
filho da direita:valor da chave maior que o valor da chave do nó pai
não há chaves duplicadas
fazer exercício: criar árvore inserindo nós na seguinte ordem:f, a, t, b, e, u, i, c, d, a, e
Nivelamento - PIPCA 2012/1 15
Classe representando um nó
public class BSTNode { protected int key; protected BSTNode left, right;
public BSTNode() { left = right = null; } public BSTNode(int num) { this(num,null,null); } public BSTNode(int num, BSTNode lt,
BSTNode rt) { this.key = num; left = lt; right = rt; } public int getKey() {
return key; } public void setKey(int key) {
this.key = key; }
public BSTNode getLeft() {return left;
}public void setLeft(BSTNode left) {
this.left = left;}public BSTNode getRight() {
return right;}public void setRight(BSTNode right) {
this.right = right;} }
Nivelamento - PIPCA 2012/1 16
Classe representando árvore
public class BST { private BSTNode root = null;
public BST() { } public void clear() { root = null; } public boolean isEmpty() { return root == null; } public BSTNode getRootNode (){ return root; }
Nivelamento - PIPCA 2012/1 17
Busca de um valor
• A procura de um valor em uma árvore binária é algo mais rápido do que a procura em listas encadeadas ou vetores.
• Para cada nó, compare a chave a ser localizada com o valor armazenado no nó correntemente apontado. – Se a chave for menor, vá para a sub-árvore esquerda e tente
novamente, – senão vá para a sub-árvore direita.
• A busca pára quando for encontrado o nó ou quando não há mais meios de continuar (nó folha), pois a chave não está na árvore.
• A complexidade pode ser medida pelo número de comparações feitas durante o processo de busca. Isso depende do número de nós encontrados no único caminho que leva da raiz ao nó procurado. Então a complexidade, depende da forma da árvore e da posição do nó procurado na árvore. O número médio de comparações em uma busca é (lg n), pois a altura de uma árvore binária completa (perfeitamente balanceada) é h=lg (n+1) .
Nivelamento - PIPCA 2012/1 18
Busca
public BSTNode search (int el) { return search(root,el);}
private BSTNode search (BSTNode p, int el) { while (p != null) { /* se valor procurado == chave do nó, retorna referência ao nó
*/ if (el==p.key) return p; /* se valor procurado < chave do nó, procurar na sub-árvore esquerda deste nó */ else if (el<p.key) p = p.left; /* se valor procurado > chave do nó, procurar na sub-árvore direita deste nó */ else p = p.right; } // caso chave não foi achada, retorna null return null;}
Nivelamento - PIPCA 2012/1 19
Inserindo uma nova chave
public boolean insert (int el) { BSTNode p = root, prev = null; // caso o valor já exista na árvore, não inserir e
retornar false if (search(el)!=null) return false; // procurando um lugar para colocar o novo nó while (p != null) { prev = p; if (el<p.key) p = p.left; else p = p.right; } // se árvore vazia if (root == null) root = new BSTNode(el); else if (prev.key<el) prev.right = new BSTNode(el); else prev.left = new BSTNode(el); return true; }
Nivelamento - PIPCA 2012/1 20
Caminhamento (percurso) em árvore binária de pesquisa
• É o processo de visitar cada nó da árvore exatamente uma vez.
• Visitar: Fazer algo com o nó como exibi-lo, gravá-lo, etc.
• O percurso pode ser interpretado como colocar todos os nós em uma linha ou a linearização da árvore.
• Os percursos podem ser em extensão ou em profundidade. – Percursos em extensão: visitam todos os nós de
cada nível, nível por nível (indo do mais alto ao mais baixo, ou vice-versa).
– Percursos em profundidade: percorre os caminhos das árvores. Percorre primeiramente todo o caminho mais a esquerda, e assim por diante.
Nivelamento - PIPCA 2012/1 21
Caminhamento (percurso) em árvore binária de pesquisa
• Os três mais comuns tipos de percursos em profundidade, definidos recursivamente, são:– PRÉ-ORDEM (raiz-esquerda-direita):
• visita o nó; • percorre a sub-árvore esquerda; • percorre a sub-árvore direita;
– PÓS-ORDEM (esquerda-direita- raiz): • percorre a sub-árvore esquerda; • percorre a sub-árvore direita; • visita o nó;
– IN-ORDEM (esquerda-raiz-direita): • percorre a sub-árvore esquerda; • visita o nó; • percorre a sub-árvore direita.
Nivelamento - PIPCA 2012/1 22
Percurso in-ordem
public void inorder() { inorder(root);}
private void inorder (BSTNode p) { if (p != null) { inorder(p.left); System.out.print(p.key + " "); inorder(p.right); }}
Nivelamento - PIPCA 2012/1 23
Percurso em pre-ordem
public void preorder() { preorder(root);}
private void preorder(BSTNode p) { if (p != null) { System.out.print(p.key + " "); preorder(p.left); preorder(p.right); }}
Nivelamento - PIPCA 2012/1 24
Percurso em pós-ordem
public void postorder() { postorder(root);}
private void postorder(BSTNode p) { if (p != null) { postorder(p.left); postorder(p.right); System.out.print(p.key + " "); } }
Nivelamento - PIPCA 2012/1 25
Remoção de um nó
• Na remoção 3 situações podem ocorrer :Caso 1: Exclusão de uma folhaO nó é uma folha e não tem filhos: O ponteiro do seu
pai é ajustado para nulo.
50
30 80
15 40 9060
50
30 80
40 9060
antes depois
Nivelamento - PIPCA 2012/1 26
Remoção de um nó
Caso 2: O nó tem um filho: o ponteiro do pai aponta para o filho deste
50
30 80
40 9060
50
40 80
9060
antes depois
Nivelamento - PIPCA 2012/1 27
Remoção de um nó
• Caso 3: O nó tem 2 filhos. Neste caso podemos fazer a remoção de duas maneiras:– remoção por cópia;– remoção por fusão
50
30 80
15 40 9060
antes
Nivelamento - PIPCA 2012/1 28
Remoção por cópia
• remove uma chave k1 (chave do nó que se quer remover):– sobrescrevendo-a por uma outra chave k2 (o
maior valor na sub-árvore esquerda, pois este vai ser maior que todos os valores da sub-árvore esquerda)
– e então removendo o nó que contem k2 (que será um dos casos simples: folha, ou nó com apenas um filho).
Nivelamento - PIPCA 2012/1 29
Remoção por cópia
1 2 3
Final
Nó que retorna referência ao nó pai de uma chave
protected BSTNode searchFather (int el) { BSTNode p = root; BSTNode prev = null;
// acha o nó p com a chave el while (p != null && !(p.key==el)) { prev = p; if (p.key<el) p = p.right; else p = p.left; } if (p!=null && p.key==el) return prev; return null; }
Nivelamento - PIPCA 2012/1 31
Remoção por cópia public void deleteByCopying (int el) { BSTNode node, father = null; node = search (el) ; // procura nó a ser deletado if (node != null && node.key==el) { if (node!=root) father = searchFather (el); // procura pai do nó a ser deletado if (node.right == null){ // nó não tem filho direito (caso 2 ou caso 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 por cópia BSTNode tmp = node.left; // 1. pegando sub-arvore esquerda while (tmp.right != null) // 2. acha a posição mais a direita da sub-árvore esquerda
do nó tmp = tmp.right;
deleteByCopying (tmp.key); // remove por copia o nó que possui o maior valor // da sub-arvore esquerda do nó a ser deletado node.key = tmp.key; // copia o valor da chave do maior nó da subárvore esquerda } } else if (root != null) System.out.println("el " + el + " is not in the tree"); else System.out.println("the tree is empty"); }
Nivelamento - PIPCA 2012/1 32
Remoção por fusão
• A solução consiste em fusionar as duas sub-árvores do nó a ser deletado em uma.
• Para tanto, 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 e torná-lo a raiz da sub-árvore direita. Também pode-se procurar o nó com menor valor da sub-árvore direita.
• Remove a chave, removendo o nó que contém a chave. E o pai do nó removido passa a apontar para a nova sub-árvore.
Nivelamento - PIPCA 2012/1 33
Remoção por fusão
1 2 3
Final
Nivelamento - PIPCA 2012/1 34
Remoção por fusãopublic void deleteByMerging (int el) { BSTNode tmp, node,father = null; node = search (el) ; // procura nó a ser deletado if (node != null && node.key==el) {
// procura pai do nó a ser removido if (node!=root) father = searchFather (el); if (node.right == null){ // nó não tem filho direito (caso 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 (caso 2) 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 por fusão tmp = node.left; // pega sub-arvore esquerda while (tmp.right != null) tmp = tmp.right; // pega filho mais a direita da sub-arvore esquerda
tmp.right = node.right; // o filho mais a direita da sub-arvore esquerda passa a
ter // como filho direito o filho direito do nó a ser deletado
if (root==node) root = node.left; else if (father.left == node) father.left = node.left; else father.right = node.left; } } else if (root != null) System.out.println("el " + el + " is not in the tree"); else System.out.println("the tree is empty"); }
Heap
• É uma estrutura de dados baseada em árvore (especializada)
• Propriedade do heap se B é filho de um nó A, então a chave(A) >= chave (B) (maior elemento na raiz). Chamada max heap. Pode-se comparar ao contrário, dai temos o min heap.
• Usado para implementar priority queues• Applet: vamos ver o funcionamento
http://people.ksp.sk/~kuko/bak/index.html
Max HEAP
Demo: construção da heap
• http://students.ceid.upatras.gr/~perisian/data_structure/HeapSort/heap_applet.html
Implementação
• A remoção do heap é feita ordenando os elementos.
• Implementação do heap através de array a:
• Indexação– filhos a[2i+1] e a[2i+2]– pais a[floor((i−1)/2)]
Heap binário -> usa-se árvore binária
Heap binário
• É um heap criado usando-se árvore binária, com duas restrições:– Propriedade de shape: árvore completa (todos os
níveis da árvores preenchidos, exceto possivelmente o último...) - preenchimento da esquerda para a direita
– Propriedade de heap: cada né á maior do que seus filhos
• Operações:– Inserção– Remoção
Nivelamento - PIPCA 2012/1 40
Exemplos
• Inserção
• Remoção da raiz do heap (maior elemento)
Nivelamento - PIPCA 2012/1 41
Outros tipos
Kd-tree 3-d2-d
Quadtree Octree
Nivelamento - PIPCA 42
BSP