Algoritmos
e Estruturas de Dados
Décima primeira aula: Árvores chanfradas
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 2
Nesta aula vamos
• Estudar as árvores chanfradas, que são umas árvores absolutamente fantásticas. • Há outras classes de árvores fantásticas,
mas não temos tempo para todas: so
many trees, so little time.
• Mesmo assim, mencionaremos as árvores AVL, as árvores rubinegras e as B-trees.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 3
Árvores chanfradas
(splay trees)
• As árvores chanfradas (splay trees) são árvores binárias de busca auto-ajustáveis. Depois de
uma operação de acesso, o elemento acedido é
promovido até à raiz.
• A ideia é acelerar os acessos subsequentes aos nós mais recentemente acedidos.
• A promoção é feita de dois em dois níveis, excepto quando o nó está no primeiro nível.
• Foram inventadas por Sleator e Tarjan em 1985. Daniel Sleator é professor na Universidade
Carnagie-Mellon e Robert Tarjan é professor na Universidade de Princeton.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 4
Promoção
• Promover um nó é subi-lo de nível,
fazendo descer o pai pelo lado contrário.
X Y c a b Y X c a b
Em ambas as árvores, num percurso directo primeiro vamos ao a, depois ao X, depois ao b, depois ao Y e depois ao c.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 5
Rotação para a direita
• A ligação XY roda para a direita:
X Y c a b Y X c a b
A promoção de um nó faz-se por meio de uma rotação da ligação ao seu pai. Neste caso, é uma rotação para a direita.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 6
Rotação para a esquerda
• A ligação XY roda para a esquerda:
Y X c a b X Y c a b
Em qualquer dos casos, se a árvore for uma árvore de busca, após a rotação continua a ser uma árvore de busca.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 7
tree_promote
• A promoção envolve um subtil rearranjo dos apontadores. • É “só” preciso ter cuidado:Tree tree_promote (Tree t) {
int side = tree_side (t); Tree p = t−>parent;
t −> parent = p−>parent; if (t−>parent != NULL)
t −> parent −> child [tree_side (p)] = t;
p −> child [side] = t−>child [!side]; if (p −> child [side] != NULL)
p −> child [side] −> parent = p; t −> child [!side] = p; p−>parent = t; return t; } Veja com cuidado!
Note que esta função roda para o lado certo, sem usar if’s.
Mudam seis apontadores
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 8
Ziguezague
• Nas árvores chanfradas, quando filho e pai estão de lados diferentes, promove-se em ziguezague:
X Y c a b d Z Y X b c a d Z Z Y b c a d X
Chama-se ziguezague porque as rotações são em sentido diferente: neste caso, primeiro
para a esquerda, depois para a direita.
Depois do ziguezague, a árvore está localmente
equilibrada no nó promovido e tanto este como as suas subárvores estão mais perto da raiz.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 9
Ziguezigue
• Quando filho e pai estão do mesmo lado, promove-se em “ziguezigue”: X Y b c a d Z Z Y d b c a X Z X b c a d Y
Note bem: neste caso primeiro promove-se o pai do nó e depois o nó.
As duas rotações são para o mesmo lado, (neste caso para a direita). Por oposição ao ziguezague, isto chama-se ziguezigue.
Depois do ziguezigue, as subárvores do nó promovido estão mais próximas da raiz.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 10
Chanfrando
• Chanfrar (to splay) um nó é promovê-lo até à raiz em ziguezague e em
ziguezigue, excepto eventualmente a
última promoção que poderá ser simples se a profundidade inicial era ímpar.
• Após aceder a um nó, chanframo-lo. Assim, se ele for acedido de novo, em
breve, será apanhado mais depressa, em média.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 11
Tree tree_splay (Tree t) {
assert (t != NULL);
while (t −> parent != NULL && t−>parent−>parent != NULL) if (tree_side (t) == tree_side (t−>parent))
{ // zigzig tree_promote (t−>parent); tree_promote (t); } else { // zigzag tree_promote (t); tree_promote (t); } if (t −> parent != NULL) tree_promote (t); return t; }
tree_splay
Enquanto não o nó t não chegar à raiz ou aos filhos da raiz, promove-se, em ziguezigue ou em ziguezague.Se ficou num filho da raiz, promove-se mais uma vez, simplesmente.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 12
splay_tree_find
• Ao procurar, se encontramos, chanframos o nó; se não encontramos, chanframos o pai “virtual” (isto é, o nó que seria o pai do nó encontrado se o valor procurado existisse):Tree splay_tree_find (Tree t, int x) {
Tree result = NULL; Tree p = t;
Tree q = NULL;
while (p && p−>value != x) { q = p; p = p−>child [p−>value < x]; } if (p == NULL) { if (q != NULL) result = tree_splay (q); } else result = tree_splay (p) ; return result; } Não encontrámos: chanframos o pai. Encontrámos: chanframos o nó.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 13
splay_tree_put
• Depois de pôr, chanframos o nó. • Isto é, se o valor não existia, chanframos o novo nó. Se já existia, chanframos o nó respectivoTree splay_tree_put (Tree t, int x) {
Tree result = NULL; Tree p = t;
Tree q = NULL; int side = 0;
while (p && p−>value != x) {
q = p;
p = p−>child [side = p−>value < x]; }
if (p == NULL)
{
assert (q == NULL || q−>value != x); result = tree_cons (x, NULL, NULL); if (q != NULL)
q−>child [side] = result; result−>parent = q;
} else
result = p;
result = tree_splay (result); return result; } Novo nó. O valor já existia, e está no nó apontado por p.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 14
splay_tree_remove
• Remove-se e chanfra-se o pai do nó removido:
Tree splay_tree_remove (Tree t) {
Tree result = NULL;
search_tree_remove (&t); if (t != NULL)
result = tree_splay (t); return result;
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 15
void test_find (void) {
Tree t = NULL; int n;
int limit; int x;
scanf ("%d%d", &n, &limit); t = search_tree_rand (n, limit);
tree_write_diagram (stdout, "%d", t, 3, 0); tree_writeln_star (stdout, t);
tree_writeln (stdout, " %d", t); printf ("−−−−−−−−−−\n");
while (scanf ("%d", &x) != EOF) {
t = splay_tree_find (t, x);
if (t == NULL || t −> value != x) printf ("not found.\n");
tree_write_diagram (stdout, "%d", t, 3, 0); tree_writeln_star (stdout, t); tree_writeln (stdout, " %d", t); printf ("−−−−−−−−−−\n"); } tree_free (&t); }
Experimentando o
splay_tree_find
Cria uma árvore com n nós, com valores aleatórios entre 0 e n.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 16
Árvores perfeitamente equilibradas
• Uma árvore é perfeitamente equilibrada se para cada nó o tamanho das suas subárvores diferir de 1 no máximo. Exemplos: 65 80 32 71 81 44 12 24 99 31 16 4 52 5 61 91 32 2 14 11 59 41 12 33 42 54 7 1 Esta não é perfeitamente equilibrada.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 17
Árvores equilibradas
• Uma árvore é equilibrada se para cada nó a altura da suas subárvores diferir de 1 no máximo. 4 12 8 9 14 15 1
• Manter uma árvore equilibrada é menos complicado do que
mantê-la perfeitamente equilibrada, ao pôr e ao remover.
Esta é equilibrada mas não perfeitamente
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 18
Árvores AVL
• Uma árvore AVL é uma árvore de busca equilibrada.
• “AVL” são as iniciais dos inventores, os matemáticos russos Adelson-Velskii e Landis (1962).
• Em certas implementações, os nós das árvores AVL têm um membro que guarda a altura da subárvore cuja raiz é esse nó (ou a diferença da altura com a subárvore “irmã”).
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 19
Árvores rubinegras (
red
-black)
• Uma árvore rubinegra (red-black tree) é uma árvore binária de busca, com
sentinela, em que cada nó tem uma de duas cores: vermelho ou preto.
• Restringindo as maneiras de colorir os nós ao longo dos caminhos da raiz até às
folhas, garante-se que nenhum caminho tem mais do dobro dos nós do que
qualquer outro. Assim, a árvore fica “aproximadamente” equilibrada.
Sentinela
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 20
Propriedades das árvores
rubinegras
• Cada nó ou é vermelho ou é preto. • A raiz é preta. • A sentinela é preta. • Se um nó é vermelho, os seus dois filhos sãopretos. • Todos os caminhos desde um nó até à sentinela têm o mesmo número de nós pretos. 3 34 20 22 21 37 55 29
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 21
B-trees
• Uma b-tree é uma árvore de busca equilibrada, desenhada para ter um bom desempenho em dispositivos de memória secundária de acesso directo.
• Os nós das b-trees podem ter muitos filhos (e não apenas dois).
• As b-trees são uma generalização das árvores binárias de busca, como mostra o exemplo:
134
24 70 160 215 244
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 22
Propriedades das B-trees
• Numa b-tree, cada nó tem vários valores e vários filhos. Os nós que são folhas não têm filhos. Os nós internos que tenham n valores têm n+1 filhos.
• O número mínimo de filhos num nó interno de uma
árvore é o grau mínimo da árvore. Se o grau mínimo
for t cada nó tem pelo menos t−1 valores. Numa b-tree de grau mínimo t, o número máximo de valores num nó é 2t−1 e, portanto, o número máximo de
filhos é 2t.
• Os valores num nó estão ordenados e separam os valores das subárvores correspondentes.
• Ao pôr e ao remover, é preciso garantir que as propriedades da b-tree se mantêm.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 23
Exercícios
• Programe as AVL com campo para a altura.
• Investigue e programa as árvores rubinegras.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 24
Controlo
• Que tipos de árvores estudámos?
• O que é o ziguezigue? E o ziguezague? • Chanframos o quê, quando o que
procuramos não existe?
• Quem inventou as splay trees? E as AVL? • Qual é a diferença entre as árvores
equilibradas e as árvores perfeitamente equilibradas.
20-06-2012 Algoritmos e Estruturas de Dados I - 11 © Pedro Guerreiro 25
Na próxima aula
• Abandonaremos as árvores e passaremos para a estrutura de dados seguinte: as