b-trees - OoCities

Propaganda
UNISINOS - UNIVERSIDADE DO VALE DO RIO DOS SINOS
CENTRO DE CIÊNCIAS EXATAS E TECNOLÓGICAS
65098 - ESTRUTURAS AVANÇADAS DE DADOS
PROFESSORA: ANA PAULA LÜDTKE FERREIRA
ALUNOS:
DATA: 06/06/2001
BRAULIO DE OLIVEIRA
IGOR DREWS
FABIO COSTA
FABIANO ARAUJO
GUILHERME LAZZARI
OTAVIO GASPARETO
RED-BLACK TREES
AVL TREES
B-TREES
QUAD-TREES
www.trees.cjb.net
[email protected]
UNISINOS
ÍNDICE
INTRODUÇÃO..................................................................................................... 3
RED-BLACK TREES ........................................................................................... 4
AVL TREES ....................................................................................................... 10
QUAD-TREES ................................................................................................... 15
B-TREES ........................................................................................................... 21
IMPLEMENTAÇÕES ......................................................................................... 28
CONCLUSÃO .................................................................................................... 39
BIBLIOGRAFIA .................................................................................................. 40
ESTRUTURAS AVANÇADAS DE DADOS
2
UNISINOS
INTRODUÇÃO
Antes de iniciarmos esta introdução, gostaríamos de lembrar que nosso site está
sempre em atualização. Pretendemos desenvolver com mais calma e clareza novos
algoritmos para as árvores apresentadas no trabalho. Caso prefira, entre em contato
conosco por e-mail. Tentaremos ajudá-lo da melhor maneira possível.
Neste trabalho demonstraremos quatro diferentes estruturas de árvores com
pesquisa O(log n). Red-Black, AVL, B-Tree e Quad-Tree serão as estruturas
demonstradas. Daremos uma explicação sobre cada uma, demonstrando seus graus de
complexidade, análise detalhada de vários casos possíveis de ocorrem durante suas
execuções e algoritmos genéricos representativos das estruturas. Apresentaremos
também, no final do trabalho, o código fonte, desenvolvido após o entendimento e
conclusões chegadas após o estudo. Tentamos, pois achamos muito válido, colocar não
só os conceitos demonstrados no seminário, como tudo o que aprendemos durante o
mesmo, seja com os alunos de outros grupos, com a professora, ou até mesmo com
entrevistas a outras entidades.
ESTRUTURAS AVANÇADAS DE DADOS
3
UNISINOS
RED-BLACK TREES
Como sabemos, ao estudarmos Árvores Binárias de Pesquisa de altura h temos
um conjunto básico de operações dinâmicas que possuem um tempo de execução O(h).
Entre elas estão a Inserção, Deleção, Pesquisa, e outras. O problema é que funcionam
bem para árvores com pouca altura. As Red-Black Trees é uma estrutura que mantém a
árvore aproximadamente balanceada, garantindo assim, que essas operações tenham
sempre um tempo O(log n), no pior caso.
Red-Black Trees é uma árvore binária com um pequena diferença. Possui um bit
extra de armazenamento da cor do nodo, que pode ser Vermelho (Red) ou Preto (Black).
A cada inserção, o algorítimo testa um conjunto de propriedades. Caso essas
ESTRUTURAS AVANÇADAS DE DADOS
4
UNISINOS
propriedades não sejam satisfeitas, rotações e/ou ajustes de cores ocorrem mantendo
assim a àrvore “balanceada”.
A àrvore estará balanceada se atender as seguintes propriedades:
1. Todo nodo é vermelho ou preto;
2. Toda folha (NIL) é preta;
3. Se um nodo é vermelho, então ambos seus filhos são pretos;
4. Todo caminho simples de um nodo para uma folha descendente contém o mesmo
número de nodos pretos.
Exemplo de uma árvore Red-Black. (Fig. 1). Podemos notar que as quatro
propriedades estão sendo satisfeitas.
Fig. 1
Chamamos de black-height de um nodo, o número de nodos pretos do nodo x
até uma folha, não incluindo esse nodo x. Denotamos a black-height por bh(x). Definese a altura de uma Red-Black como a black-height de sua raiz.
ESTRUTURAS AVANÇADAS DE DADOS
5
UNISINOS
Rotações
Ao inserirmos ou deletarmos em uma árvore Red-Black temos uma violação de
suas propriedades. Para manter a árvore O(log n) e “balanceada”, realizamos
rotações, que podem ser para a esquerda ou para direita. Em alguns casos
realizaremos rotações duplas para a esquerda ou duplas para a direita.
Tanto a Left-Rotate como a Right-Rotate executam em O(1). Ocorrem apenas
mudanças com ponteiros, sendo que os outros campos do nodo permanecem
inalterados. Veremos adiante que as mesmas rotações serão usadas nas árvores
AVL. Veja no exemplo o resultado das rotações. (Fig. 2)
Fig. 2
Pseudo-código do Left-Rotate, assumindo que right[x] <> NIL.
Inserção
Para que haja um melhor entendimento da Inserção nesse tipo de árvore,
vamos estudar um caso passo a passo.
1º) Vamos pegar como o exemplo a árvore da Fig. 1.
2º) Agora iremos inserir o nodo com o valor 4, que chamaremos de x. Podemos ver
que temos dois nodos vermelhos seguidos e, o tio y de x é vermelho. Temos o caso 1.
ESTRUTURAS AVANÇADAS DE DADOS
6
UNISINOS
3º) Trocamos as cores dos nodos 4, 7 e 8.
4º) Movemos x para seu avô, 7. O pai de x, o nodo 2, ainda é vermelho. Marcamos o
tio de x como y, que é preto. Neste caso temos o caso 2.
5º) Movemos x para cima e aplicamos uma rotação para a esquerda.
ESTRUTURAS AVANÇADAS DE DADOS
7
UNISINOS
6º) Mesmo o tio de x é sendo preto, o pai de x impede que tenhamos uma Red-Black.
7º) Alteramos as cores dos nodos 7 e 11 e rotacionamos para a direita.
ESTRUTURAS AVANÇADAS DE DADOS
8
UNISINOS
8º) Agora sim temos a nova Red-Black Tree, “balanceada”, em O(log n).
Deleção
O caso da deleção é levemente mais complicado, mas funciona basicamente
como a inserção, precisando sempre fazer os ajustes baseados nas propriedades da RedBlack, garantindo assim que ela fique balanceada. Não falaremos sobre deleção neste
trabalho. Pretendemos assim estudarmos mais a fundo a questão das vantagens de se ter
uma árvore balanceada.
ESTRUTURAS AVANÇADAS DE DADOS
9
UNISINOS
AVL TREES
O nome AVL vem de seus inventores Adelson-Velskii and Landis. Foi a primeira
proposta de balanceamento de árvores binárias de pesquisa. É aproximadamente
balanceada. Suas sub-árvores diferença de altura de no máximo 1 nível, garantindo assim
a execução em O(log n). Vale lembrar que as árvores AVL são muito parecidas com as
Red-Black, tanto que as rotações, por exemplo, que veremos logo em seguida são as
mesmas.
Uma árvore AVL é uma árvore de pesquisa binária com as seguintes
propriedades:
1. A sub-árvore de todo nodo difere em altura por no máximo 1 nível;
2. Toda sub-árvore é uma AVL Tree.
ESTRUTURAS AVANÇADAS DE DADOS
10
UNISINOS
Temos aqui um esquema de como deve ser a árvore AVL para que ela seja
considerada balanceada.
Podemos notar nos exemplos abaixo dois casos de árvores binárias. A primeria é
uma AVL, já a segunda não. Vamos a uma melhor análise:
1º) Note que cada sub-árvore esquerda tem altura 1 maior que cada sub-árvore
direita, portanto é uma AVL.
2º) A sub-árvore com raiz 8 tem altura 4 e sub-árvore com raiz 18 com altura 2.
ESTRUTURAS AVANÇADAS DE DADOS
11
UNISINOS
Procedimentos básicos
A Inserção é um pouco complicada pois envolve vários casos, como as RedBlacks. Cada nodo, ao invés de ter um bit para a cor, terá um campo extra controlando
seu fator de balanceamento. Este fator indica se a árvore está left-heavy ( a altura da subárvore esquerda é 1 maior que a sub-árvore direita), balanceada (ambas sub-árvores tem
a mesma altura) ou right-heavy (a altura da sub-árvore direita é 1 maior que a sub-árvore
esquerda).
Para que mantenhamos a árvore “balanceada”, garantindo execução em tempo
O(log n), precisamos realizar rotações, que são as mesmas das árvores Red-Black, como
já dito anteriormente. Elas são necessárias pois a cada inserção há uma verificação da
altura dos nodos da árvore.
Na figura acima, vemos que um novo nodo foi adicionado à esquerda do nodo 1,
fazendo com que a altura de 2 maior que que a direita (verde). Uma rotação à direita é
executada e então a árvore torna-se balanceada.
Seja um nó qualquer da árvore, apontado por n:

se FatBal(n) = 0, as duas subárvores têm a mesma altura;

se FatBal(n) = -1, a subárvore esquerda é mais alta que a direita em 1;

se FatBal(n) = +1, a subárvore direita é mais alta que a esquerda em 1.
A vantagem de uma árvore AVL sobre uma degenerada (desbalanceada) está na
maior eficiência nas suas operações de busca, pois, sendo a altura da AVL bem menor, o
ESTRUTURAS AVANÇADAS DE DADOS
12
UNISINOS
número necessário de comparações diminui sensivelmente. Por exemplo, numa árvore
degenerada de 10.000 nós, são necessárias, em média, 5.000 comparações, numa
busca; numa árvore AVL, com o mesmo número de nós, essa média baixa para 14.
Inserção
Sabemos que a inserção sempre se dá numa folha, podendo assim alterar os
fatores de balanceamento e desequilibrar a árvore. O algoritmo que apresentamos fará a
inserção seguida do ajuste dos fatores de balanceamento e, se houver desequilíbrio
(algum FatBal(n) diferente de -1, 0 ou +1), corrigirá a estrutura fazendo rotação de nós.
Rotação
Como a árvore está desbalanceada à esquerda, há uma rotação simples para
direita, demonstrada abaixo.
No próximo caso há um desajuste à direita, ocorrendo assim uma rotação simples
para a esquerda.
Dois outros tipos de rotações são usados para ajustes de balanceamento. Rotação
dupla para a esquerda e dupla para a direita. O primeiro é composta de uma simples à
esquerda seguida de uma simples à direita. A rotação dupla para a direita é o inverso.
ESTRUTURAS AVANÇADAS DE DADOS
13
UNISINOS
Nunca é demais lembrar, como muitas vezes já falado, que essas rotações ocorrem nas
árvores Red-Black também. A diferença é que as Red-Black se baseiam na cor do nodo
como fator de balanceamento, já ás AVLs analisam a altura de cada sub-árvore de cada
nodo.
ESTRUTURAS AVANÇADAS DE DADOS
14
UNISINOS
QUAD-TREES
Uma Quad-Tree é uma estrutura de dados utilizada para codificar imagens. A idéia
fundamental atrás da Quad-Tree é que qualquer imagem pode ser dividida em quatro
quadrantes. Sendo que cada quadrante pode ser dividido novamente em quatro
subquadrantes e assim sucessivamente.
Na Quad-Tree, a imagem é representada por um nodo pai, enquanto que os
quatro quadrantes são representados por quatro nodos filho, em uma ordem prédeterminada. Sendo que a Quad-Tree é um tipo especial de árvore onde todos os nodos
ou são nodos folha ou têm quatro nodos filho. Tendo como utilização principal o
armazenamento de uma decomposição recursiva do espaço.
O algoritmo verifica se a imagem possui apenas uma única cor, em caso positivo é
criado apenas um nodo com a informação da respectiva cor.
Caso contrário a imagem é dividida em 4 quadrantes, sendo que inicialmente a
quadtree gerada deverá ser um nodo pai com quatro nodos filho (representando os quatro
quadrantes), agora é feita uma nova verificação em cada quadrante para ver se cada um
possui uma única cor em seu respectivo quadrante, se for constatado isso, o respectivo
ESTRUTURAS AVANÇADAS DE DADOS
15
UNISINOS
nodo filho recebe a informação da cor (se tornando um nodo cor), caso contrário, esse
quadrante será subdividido em 4 subquadrantes e uma nova verificação será feita em
cada um deles sucessivamente, até que o quadrante da imagem possua apenas uma
única cor. Sendo que a cada nova subdivisão o nodo atual se torna pai de quatro novos
nodos e quando a subdivisão cessa a informação da cor é inserida no nodo (se tornando
um nodo cor). Ou em outras palavras, os nodos folha correspondem às regiões onde não
há mais necessidade de subdivisão contendo a informação da cor resultante. (Fig. 1)
Imagem
QuadTree Resultante
Figura 1: Os nodos na cor cinza são os nodos onde ocorreu a dividsão da imagem em quatro quadrantes. São portanto nodos-pai.
Criação da árvore
O algoritmo de criação recebe dois parâmetros: a raiz da árvore e uma imagem
(lida como String). Em seguida, este algoritmo verifica se a imagem possui somente uma
cor. Se possuir, então esta cor é colocada no campo COR do único nodo criado até este
momento, que também foi recebido como parâmetro por este algoritmo (Raiz).
Se não possuir uma cor somente, então, a imagem passada como parâmetro é dividida
em quatro quadrantes iguais e cria-se quatro novos nodos, que serão filhos do nodo raiz
recebido como parâmetro. Estes quatro quatros quadrantes normalmente são
identificados por NO (Noroeste), NE (Nordeste), SO (Sudoeste) e SE (Sudeste). Em
materiais em inglês eles serão identificados por NW, NE, SW ou SE, por motivos óbvios.
ESTRUTURAS AVANÇADAS DE DADOS
16
UNISINOS
Assim, mesma função é aplicada, recursivamente, em cada um dos quatros quadrantes. A
recursão irá terminar quando se chegar um quadrante que possuam somente uma cor,
para daí armazenar as informações de cor em nodo Folha.
É interessante ressaltar que uma Quad-Tree possuirá 2 estruturas de Nodo:
Nodo Interno: É nodo que possuirá 4 ponteiros para suas subdvisões. Este tipo
de nodo não irá armazenar nenhuma informação de imagem propriamente, assim não
encontraremos nele informações como cor ou tamanho.
Nodo Folha: É o nodo que irá se encarregar de armazenar informações da cor da
Imagem.
Não necessariamente, qualquer Quad-Tree possuirá estes dois tipos de nodo. Por
exemplo, se uma imagem passada como parâmetro for sólida de uma cor só, teremos
somente o nodo raiz, que na realidade será um nodo folha, pois armazenará diretamente
as informações de cor.
Inserção
A inserção de nodos em uma QuadTree se dará em dois momentos:
Na criação de uma QuadTree: Este processo foi exaustivamente explicado no item
anterior. Nele, vemos que a partir da leitura da Imagem, iremos incluir Nodos Folha
ou Nodos Internos, dependendo das cores do quadrante em questão.
Na Alteração da Imagem a partir da qual a QuadTree foi gerada: No momento em
que temos uma Quad-Tree gerada a partir de uma imagem, e alteramos a imagem,
podemos optar por criar novamente toda a Quad-Tree ou simplesmente incluir novos
nodos que reflitam as alterações realizadas.
A Inserção se dará a partir de uma pesquisa recursiva na QuadTree, até
chegarmos ao Quadrante em questão, representado por um Nodo Folha. No momento em
que encontramos tal nodo, devemos retirar a informação de cor que o mesmo possuía,
criar novos nodos, quantos forem necessários (recursivamente), que serão descendentes
do nodo inicial. Nos novos nodos serão armazenadas as informações de cor que reflitam
ESTRUTURAS AVANÇADAS DE DADOS
17
UNISINOS
as alterações realizadas na imagem. O exemplo abaixo ilustra o conceito de inclusão
abordado.
Deleção
A exclusão de Nodos poderá ser realizada quando um determinado nodo interno
tem todos os seus descendentes armazenando a mesma cor. Quando isto ocorre, podese excluir todos os nodos descendentes e armazenar a cor no ancestral correspondente.
Imagem
ESTRUTURAS AVANÇADAS DE DADOS
QuadTree Resultante
18
UNISINOS
Figura 3: Imagem inicial com sua respectiva quadtree, depois o 2º quadrante da imagem é todo pintado de vermelho, tornando os
quatro nodos filhos de seu nodo pai com a cor vermelha. E para não haver desperdício de quatro nodos para uma mesma cor, esses
são excluídos e o nodo pai passe a ser nodo folha com a informação da cor vermelha. Um caso onde houve alteração das cores dos
nodos e para não haver desperdício houve também exclusão dos mesmos.
Pesquisa
Tem-se várias formas de pesquisa em QuadTrees. Abordaremos a que
consideramos mais importante: a Pesquisa por Cor.
A pesquisa por cor varre toda a QuadTree gerada, tentado localizar uma cor específica. A
aplicação prática para este tipo de pesquisa seria a realização de operações de troca de
cores em imagens. Por exemplo, em uma determinada imagem deseja-se que tudo que
aparece em Verde seja mostrado em Azul. Este tipo de aplicação, tem uso prático na
medicina, onde em determinadas radiografias, células defeituosas são mostradas em
cinza, que seria a sua cor natural, porém para visualizá-las melhor pode-se trocar a sua
cor para preto.
Caminhamentos
Temos algumas formas de caminhamentos em Quad-Trees, que podem ser:
ESTRUTURAS AVANÇADAS DE DADOS
19
UNISINOS
Aplicações



3D Studio MAX 3 (um dos mais populares softwares para animação e
renderização de imagens 3D): É utilizado aqui a quadtree para se fazer o controle
da profundidade de cor para sombras RayTrace.
Corrigir deformaçôes de cores nas fotos. Como por exemplo, quando se tira uma
foto e a pessoa está com os olhos avermelhados, podendo isso ser corrigido
utilizando a quadtree.
Compactação de imagens.
Vantagens e desvantagens de seu uso
Uma grande vantagem é que sua estrutura é bastante robusta e compacta, mas
existem alguns fatores que a tornam, em outros casos, inviáveis.



Se a imagem tem grandes áreas com uma única cor (como por exemplo: o preto
ou branco) haverá um grande ganho em espaço e uma árvore bastante compacta,
mas se a imagem tenha grandes áreas com diferentes cores (como por exemplo:
azul, amarelo, verde, etc...) a árvore resultante será muito maior não
proporcionando um ganho considerável em espaço.
Um considerável consumo de CPU quando se trabalha com imagens complexas
(diversas cores, formas irregulares como curvas e triângulos, etc) na geração da
árvore.
Não há balanceamento, podendo ocorrer de nodos muito extensos de um lado e
de outro muito curto, deixando a busca um pouco lenta.
ESTRUTURAS AVANÇADAS DE DADOS
20
UNISINOS
B-TREES
São árvores de pesquisa balanceada feitas para trabalhar bem em discos
magnéticos ou outros dispositivos de armazenamento secundários com acesso direto. BTrees são similares às Red-Blacks, mas elas são melhores pois minimizam operações de
entrada e saída no disco.
B-Trees podem ter muitos filhos, diferenciando-se assim das Red-Blacks. Assim, o
fator de ramificação de desse tipo de árvore pode ser muito grande, sendo determinado
pelas características da unidade de disco. São parecidas com as Red-Blacks também,
pois todos nodo n de uma B-Tree tem altura O(log n), mas conseguem ser menor que as
Red-Blacks, porque o fator de ramificação pode ser muito grande. Sendo assim, B-Trees
podem ser usadas na implementação de um conjunto de operações dinâmicas em tempo
O(log n).
B-Trees generalizam árvores de pesquisa binária de uma melhor maneira. Se um
nodo x de uma B-Tree contém n[x] elementos, então x tem n[x]+1 filhos. Os elementos em
um nodo x são usados como pontos de divisão separando a área dos elementos
manuseados por x em n[x] + 1 sub-áreas, cada manuseio por um filho de x. Quando
ESTRUTURAS AVANÇADAS DE DADOS
21
UNISINOS
procuramos por um elemento em uma B-Tree, nós fazemos em (n[x] + 1) modos de
decisão baseados em comparações com n[x] elementos armazenados no nodo x.
M
DH
BC
FG
Q T X
JKL
NP
RS
VW
YZ
Veja na figura acima uma B-Tree onde os elementos são consoantes de inglês.
Um nodo interno x contendo n[x] elementos tem n[x] + 1 filhos. Todos com a mesma altura
na árvore. Note que a altura da uma B-Tree cresce logaritmicamente com o número de
nodos que ela contém.
Acompanhe abaixo a definição mais detalhada de uma B-Tree.
Obs.: Adotaremos
key = elemento.
leaf = folha
root = raiz
Um B-Tree é uma árvore enraizada, com raiz root[T] tendo as seguintes
propriedades:
1. Todo nodo x tem os seguintes campos:
a)
n[x], o número de elementos atualmente armazenados em um nodo
b)
os mesmos n[x] elementos, armazenados em ordem crescente:
x.
key1[x] <= key2[x] <= ...<= keyn[x], e
c)
a folha[x], um valor booleano que é True or False, representando se
x é uma folha ou nodo interno, respectivamente.
2. Se x é um nodo interno, ele contém n[x] + 1 ponteiros c1[x], c2[x],...cn[x]+1
para seus filhos. Nodos folha não tem filhos, assim os campos ci são indefinidos
ESTRUTURAS AVANÇADAS DE DADOS
22
UNISINOS
3. Os elementos keyi[x] separa os tamanho dos elementos armazenados em
cada sub-árvore. Se ki é um elemento armazenado em uma sub-árvore com raiz ci[x],
então:
K1 <= key1[x] <= k2 <= key2[x],...<=key[n]x[x] <= kn[x]+1
4. Toda folha tem a mesma profundidade, que é a altura h da árvore.
5. Há limites abaixo e acima do número de elementos que um nodo pode
conter. Estes limites podem ser expressos em termos de um inteiro fixo t >= 2
chamado de grau mínimo de uma B-Tree.
a)
Todo outro nodo além da raiz tem no mínimo t – 1 elementos. Todo
outro nodo interno como a raiz tem no mínimo t filhos. Se a árvore não é vazia, a
raiz precisa ter no mínimo um elemento.
b)
Todo nodo pode contém no máximo 2t – 1 elementos. Um nodo
interno pode ter no máximo 2t filhos. Nós sabemos que um nodo é cheio se ele
contém exatamente 2t – 1 elementos.
A B-Tree mais simples ocorre quando t = 2. Todo nodo interno então tem entre 2, 3
ou 4 filhos, e nós temos árvore 2, 3, 4. Na prática, de qualquer modo, valores muito
grandes de t são tipicamentes usados.
Altura de uma B-Tree
O número de acessos a disco requeridos pela maioria das operações em uma BTree é proporcional à altura da B-Tree. Vamos analizar em seguida, a altura no pior caso
da árvore.
Teorema:
Se n >= 1, então para todo elemento n-key T de uma B-Tree de altura h e grau
mínimo t >= 2,
h <= logt n+1 / 2
ESTRUTURAS AVANÇADAS DE DADOS
23
UNISINOS
1
t-1
t-1
t
t
t t-1
t-1
...........
...........
t-1
...........
0
1
1
2
t-1
2
2t
..........
3
2t2
Prova: Se uma B-Tree tem algura h, seu número de nodos é minimizado quando a
raiz contém um elemento e todos outros nodos contém t – 1 elementos. Neste caso, há 2
nodos com profundidade 1, 2t nodos e profundidade 2, 2t2 nodos e profundidade 3, e
assim por diante, até a profundidade h ter 2th-1 nodos. Na figura acima podemos ver
claramente uma árvore com altura h = 3. O número n de elementos satisfaz a inequação.
n >= 1 + (t - 1)  2ti-1
= 1 + 2(t - 1)( th – 1 / t-1)
= 2th – 1
demonstrando o Teorema.
Podemos notar a força de uma B-Tree se comparada com uma Red-Black. A
altura da B-Tree cresce O(log n) em ambos os casos(vale lembrar que t é uma constante).
Nas B-Trees a base logarítmica pode ser muito grande. Essas árvores salvam um fator de
aproximadamente log t acima das Red-Black no número de nodos examinados para mais
de três operações. Como, ao examinarmos um determinado nodo em uma árvore requer
um acesso à disco, o número de acessos à disco é reduzido substancialmente com BTrees.
Adotaremos agora, para demonstrar as operações básicas em uma B-Tree que:

A raiz de uma B-Tree está sempre na memória principal, assim, a leitura de
disco na raiz é sempre requerida. Uma escrita no disco da raiz é requerido, quando a
raiz é mudada.
ESTRUTURAS AVANÇADAS DE DADOS
24
UNISINOS

Nenhum nodo que passados por parâmetros precisa já ter tido uma leitura
de disco.
Criando uma B-Tree Vazia
Usaremos uma procedure B-Tree Create e após uma B-Tree Insert que adicionará
novos nodos. As duas usam, para alocar uma página no disco um Allocate-Node, que
executa em O(1).
A operação básica na inserção de um elemento em uma B-Tree é o Splitting, que
irá dividir um nodo inteiro com 2t – 1 elementos baseados em sua mediana em dois outros
tendo t – 1 elementos cada. O tempo gasto pela CPU é de O(t).
Inserção de um elemento
Resumindo vamos ter o seguinte:

Um elemento só é inserido na folha e se o nodo não estiver cheio.

Se o nodo estiver cheio, o elemento central vai o nodo acima ordenadamente e o
elemento à direita vai para um novo nodo à direita, reorganizando os ponteiros.
Uma explicação mais detalhada agora.
Uma inserção de um elemento k em uma B-Tree de altura h leva O(h) acessos de disco.
O tempo requerido pela CPU é O(th) = O(t logt n). Garantimos através do B-Tree Split
Child que a recursão nunca descenderá para um nodo cheio. Usaremos uma outro
procedura auxiliar B-Tree Insert NonFull que garante que o nodo não está cheio,
retornando verdadeiro neste caso.
Para um melhor entendimento, vamos acompanhar o exemplo abaixo de uma inserção de
um elemento.
ESTRUTURAS AVANÇADAS DE DADOS
25
UNISINOS
O grau mínimo t para esta B-Tree é 3, então um nodo pode ter no máximo 5 valores. Os
nodos serão modificados durante a inserção.
a) Árvore inicial para este exemplo.
GMPX
ACDE
JK
NO
RSTUV
YZ
b) Inserindo B na árvore. É uma inserção normal em um nodo folha.
GMPX
ABCDE
JK
NO
RSTUV
YZ
c) Agora temos a inserção do valor Q. O nodo RSTUV é dividido em dois nodos
contendo RS e UV, o T é movido para a raiz e Q é inserido no ramo mais
esquerdo(nodo RS).
P
GM
ABCDE
TX
JKL
NO
QRS
UV
YZ
d) Agora podemos acompanhar a inserção do valor L na árvore. A raiz é dividida pelo
lado direito, desde que esteja cheia, e o grau da B-Tree em altura é aumentado
em uma unidade. O L é inserido em uma folha contendo JK.
P
CGM
AB
DEF
TX
JKL
NO
QRS
UV
YZ
e) O resultado da inserção de F na árvore. O nodo ABCDE é dividido antes de F e
este é inserido mais à direita dos dois valores (nodo DE).
ESTRUTURAS AVANÇADAS DE DADOS
26
UNISINOS
Deleção
A deleção em uma B-Tree é similar ao procedimento de inserção, mas um pouco
mais complicado.
Há uma série de casos que podem ocorrer durante a deleção, mas que não vão
ser estudados neste trabalho.
Para conhecimento, a complicada procedure de deleção de uma B-Tree leva
somente O(h) operações de disco, desde que somente O(1) chamadas a leitura e escrita
no disco são feitas entre invocações recursivas desta procedure. O tempo requerido pela
CPU é O(th) = O(t logt n).
ESTRUTURAS AVANÇADAS DE DADOS
27
UNISINOS
IMPLEMENTAÇÕES
Abaixo seguem as implementações das árvores apresentadas no trabalho.
Algumas das árvores implementadas contém apenas a estrutura, cabendo ao
programador definir a melhor forma de implementação.
RED-BLACK
struct t_red_black_node {
enum { red, black } colour;
void *item;
struct t_red_black_node *left,
*right,
*parent;
left_rotate( Tree T, node x ) {
node y;
y = x->right;
/* Turn y's left sub-tree into x's right sub-tree */
x->right = y->left;
if ( y->left != NULL )
y->left->parent = x;
/* y's new parent was x's parent */
ESTRUTURAS AVANÇADAS DE DADOS
28
UNISINOS
y->parent = x->parent;
/* Set the parent to point to y instead of x */
/* First see whether we're at the root */
if ( x->parent == NULL ) T->root = y;
else
if ( x == (x->parent)->left )
/* x was on the left of its parent */
x->parent->left = y;
else
/* x must have been on the right */
x->parent->right = y;
/* Finally, put x on y's left */
y->left = x;
x->parent = y;
}
rb_insert( Tree T, node x ) {
/* Insert in the tree in the usual way */
tree_insert( T, x );
/* Now restore the red-black property */
x->colour = red;
while ( (x != T->root) && (x->parent->colour == red) ) {
if ( x->parent == x->parent->parent->left ) {
/* If x's parent is a left, y is x's right 'uncle' */
y = x->parent->parent->right;
if ( y->colour == red ) {
/* case 1 - change the colours */
x->parent->colour = black;
y->colour = black;
x->parent->parent->colour = red;
/* Move x up the tree */
x = x->parent->parent;
}
else {
/* y is a black node */
if ( x == x->parent->right ) {
/* and x is to the right */
/* case 2 - move x up and rotate */
x = x->parent;
left_rotate( T, x );
}
/* case 3 */
x->parent->colour = black;
x->parent->parent->colour = red;
right_rotate( T, x->parent->parent );
}
}
else {
/* repeat the "if" part with right and left
exchanged */
}
ESTRUTURAS AVANÇADAS DE DADOS
29
UNISINOS
/* Colour the root black */
T->root->colour = black;
}
ESTRUTURAS AVANÇADAS DE DADOS
30
UNISINOS
AVL
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <alloc.h>
#include <process.h>
#include <dos.h>
#define true 0
#define false 1
/* definicao da estrutura */
typedef struct nodo {
int
info;
int
FatBal;
struct nodo *esquerda;
struct nodo *direita;
} T_nodo;
T_nodo *PtrRaiz, *PtrTrb, *PtrAnt, *PtrA, *PtrB, *PtrAAnt, *PtrNovo;
int PosChave;
T_nodo *cria_nodo(int, T_nodo *, T_nodo *, T_nodo *);
int BuscaAvl(int);
void insereAvl(int);
void AjustaFatoresAvl(int);
void BalanceiaAvl(int);
void RotacaoSimples();
void RotacaoDupla();
/* funcao principal do programa */
void main()
{
int numero=0, achou;
clrscr();
PtrRaiz=NULL;
do
{
gotoxy(5,5);
printf("Entre com a informacao : ");
scanf("%i",&numero);
if (numero != -1)
{
achou=BuscaAvl(numero);
if (achou == 1)
{
insereAvl(numero);
ESTRUTURAS AVANÇADAS DE DADOS
31
UNISINOS
AjustaFatoresAvl(numero);
BalanceiaAvl(numero);
}
else
{
gotoxy(25,22);
printf("Tentativa de insercao de chave j existente");
delay(500);
}
}
} while (numero != -1);
}
/* funcao que procura se uma chave j foi inserida */
int BuscaAvl(int numero)
{
PtrAAnt = NULL;
PtrAnt = NULL;
PtrTrb = PtrRaiz;
PtrA = PtrRaiz;
while (numero != PtrTrb->info && PtrTrb != NULL)
{
if (PtrTrb->FatBal != 0)
{
PtrA = PtrTrb;
PtrAAnt = PtrAnt;
}
PtrAnt = PtrTrb;
if (numero < PtrTrb->info)
PtrTrb = PtrTrb->esquerda;
else
PtrTrb = PtrTrb->direita;
}
if (PtrTrb == NULL)
return(1);
else
return(0);
}
/* funcao de alocacao de uma nova estrutura do tipo nodo */
T_nodo *cria_nodo(int numero)
{
T_nodo *novo;
novo=(T_nodo *) malloc(sizeof(struct nodo));
if (novo == NULL)
{
gotoxy(25,22);
printf("Memoria insuficiente para alocar estrutura");
exit(1);
}
ESTRUTURAS AVANÇADAS DE DADOS
32
UNISINOS
novo->info=numero;
novo->FatBal=0;
novo->esquerda=NULL;
novo->direita=NULL;
return(novo);
}
/* funcao que coloca um elemento na arvore */
void insereAvl(int numero)
{
PtrNovo = cria_nodo(numero);
if (PtrRaiz != NULL)
if (numero < PtrAnt->info)
PtrAnt->esquerda = PtrNovo;
else
PtrAnt->direita = PtrNovo;
else
PtrRaiz=PtrNovo;
}
void AjustaFatoresAvl(int numero)
{
if (PtrA != NULL || PtrB != NULL)
{
if (numero < PtrA->info)
{
PtrB = PtrA->esquerda;
PtrTrb = PtrA->esquerda;
}
else
{
PtrB = PtrA->direita;
PtrTrb = PtrA->direita;
}
while (PtrTrb->info != numero)
{
if (numero < PtrTrb->info)
{
PtrTrb->FatBal = -1;
PtrTrb = PtrTrb->esquerda;
}
else
{
PtrTrb->FatBal = 1;
PtrTrb = PtrTrb->direita;
}
}
}
else if (PtrRaiz->esquerda != NULL || PtrRaiz->direita != NULL)
if (PtrRaiz->esquerda == NULL) // se nulo na esquerda
ESTRUTURAS AVANÇADAS DE DADOS
33
UNISINOS
else
PtrRaiz->FatBal = 1;
// senao
PtrRaiz->FatBal = -1;
// insercao feita na direita
// insercao feita na esquerda
}
void BalanceiaAvl(int numero)
{
if (PtrA != NULL && PtrB != NULL)
{
if (numero < PtrA->info)
PosChave = -1;
else
PosChave = 1;
if (PtrA->FatBal == 0)
PtrA->FatBal = PosChave;
else
if (PtrA->FatBal == PosChave -1)
PtrA->FatBal =0;
else
{
if (PtrB->FatBal == PosChave)
RotacaoSimples();
else
if (PtrB->FatBal == -PosChave)
RotacaoDupla();
if ((PtrAAnt != NULL) && (PtrRaiz->esquerda != NULL ||
PtrRaiz->direita != NULL))
if (PtrAAnt->direita == PtrA)
PtrAAnt->direita = PtrTrb;
else
PtrAAnt->esquerda = PtrTrb;
if (PtrB->direita == PtrRaiz || PtrB->esquerda == PtrRaiz)
PtrRaiz = PtrB;
}
}
}
void RotacaoSimples()
{
if (PtrA->FatBal == 1)
{
PtrA->direita = PtrB->esquerda;
PtrB->esquerda = PtrA;
}
else
{
PtrA->esquerda = PtrB->direita;
PtrB->direita = PtrA;
}
PtrTrb = PtrB;
PtrA->FatBal = 0;
ESTRUTURAS AVANÇADAS DE DADOS
34
UNISINOS
PtrB->FatBal = 0;
}
void RotacaoDupla()
{
if (PtrA->FatBal == 1)
{
PtrTrb = PtrB->esquerda;
PtrB->esquerda = PtrTrb->direita;
PtrTrb->direita = PtrB;
PtrA->direita = PtrTrb->esquerda;
PtrTrb->esquerda = PtrA;
}
else
{
PtrTrb = PtrB->direita;
PtrB->direita = PtrTrb->esquerda;
PtrTrb->esquerda = PtrB;
PtrA->esquerda = PtrTrb->direita;
PtrTrb->direita = PtrA;
}
if (PtrTrb->FatBal == -PosChave)
{
PtrA->FatBal = 0;
PtrB->FatBal = PosChave;
}
if (PtrTrb->FatBal == 0)
{
PtrA->FatBal = 0;
PtrB->FatBal = 0;
}
if (PtrTrb->FatBal == PosChave)
{
PtrA->FatBal = -PosChave;
PtrB->FatBal = 0;
}
PtrTrb->FatBal = 0;
}
ESTRUTURAS AVANÇADAS DE DADOS
35
UNISINOS
QUAD-TREE
search(typedef key, tree t)
{
int i, indx, noteq;
while(t != NULL)
{
indx = noteq = 0;
for (i=0; i<K; i++)
{
indx = indx << 1;
if (key[i] > t->k[i]) indx++;
if (key[i] != t->k[i]) noteq++;
}
if ( noteq ) t = t->p[indx];
else { found( t ); return; }
}
notfound( key );
};
/**************************************************/
tree insert(typedef key, tree t)
{
int i, indx, noteq;
if (t==NULL) t = NewNode( key );
else
{
indx = noteq = 0;
for (i=0; i<K; i++)
{
indx = indx << 1;
if ( key[i] > t->k[i] ) indx++;
if ( key[i] != t->k[i] ) noteq++;
}
if ( noteq ) t->p[indx] = insert( key, t->p[indx] );
else Error; /*** chave já existe ***/
}
return( t );
};
ESTRUTURAS AVANÇADAS DE DADOS
36
UNISINOS
B-TREE
/*-------------------------------------------------------------------*/
/* Estrutura da árvore /-- ------------------------------------*/
typedef struct btnode
{
int d;
/*** number of active entries ***/
typekey k[2*M];
/*** chave ***/
struct btnode *p[2*M+1];
/*** ponteiros para as sub-arvores ***/
} node, *btree;
/*-------------------------------------------------------------------*/
/* Insercao /-----------------------------------------------------*/
typekey InternalInsert(typedef key, btree t)
{
int i, j;
typekey ins;
btree tempr;
extern btree NewTree;
if (t == NULL)
{
NewTree = NULL;
return(key);
}
else
{
for ( i=0; i<t->d && key>t->k[i]; i++ );
if ((i<t->d) && (key == t->k[i]))
return Error; /*** chave já existente ***/
else
{
ins = InternalInsert(key, t->p[i]);
if (ins != NoKey)
/*** the key in "ins" has to be inserted in present node ***/
if (t->d < 2*M) InsInNode( t, ins, NewTree );
else
{/*** cria um novo nodo ***/
if ( i<=M )
{
tempr = NewNode( t->k[2*M-1], NULL, t->p[2*M] );
t->d--;
InsInNode(t, ins, NewTree);
}
else tempr = NewNode( ins, NULL, NewTree );
/*** move chaves e ponteiros ***/
for (j=M+2; j<=2*M; j++)
ESTRUTURAS AVANÇADAS DE DADOS
37
UNISINOS
InsInNode(tempr, t->k[j-1], t->p[j]);
t->d = M;
tempr->p[0] = t->p[M+1];
NewTree = tempr;
return( t->k[M] );
}
}
return( NoKey );
}
};
btree insert( typedef key, btree t )
{
typekey ins;
extern btree NewTree;
typekey InternalInsert();
ins = InternalInsert( key, t );
if (ins != NoKey)
return(NewNode(ins, t, NewTree));
return(t);
};
ESTRUTURAS AVANÇADAS DE DADOS
38
UNISINOS
CONCLUSÃO
Após a realização deste trabalho, juntamente com o seminário e conceitos
aprendidos em aula conseguimos compreender alguns métodos de balanceamento de
árvores.
Chegamos à conclusão que o uso desses métodos, devidamente escolhido para
cada ocasião ou problema a ser desenvolvido, só nos traz vantagens. A principal razão é
que teremos sempre acesso em tempo logarítmico, o que é muito bom.
Resolvemos com o uso dessas estruturas, por exemplo, o problema de uma
inserção ordenada em uma árvore binária, onde teríamos uma enorme ramificação para o
lado direito da árvore. O grande problema aqui é o tempo de pesquisa, onde, mantendo
balanceada, conseguimos esse mesma pesquisa em tempo logarítmico.
ESTRUTURAS AVANÇADAS DE DADOS
39
UNISINOS
BIBLIOGRAFIA
CORMEN, Thomas; LEISERSON, Charles; RIVEST, Ronald. Introduction to
Algorithms. MIT Press, 1996
SHAFFER, Clifford A. A Practical Introduction to Data Structures and Algorithm
Analysis. Prentice-Hall, 1996.
KNUTH, D. E. The Art of Computer Programming: Sorting and Searching.
Addison-Wesley, 1997.
Sites na Web:
http://www.eli.sdsu.edu/courses/fall95/cs660/notes/RedBlackTree/RedBlack.html
http://www.inf.unisinos.br/~anibal
http://whatis.techtarget.com/
ESTRUTURAS AVANÇADAS DE DADOS
40
UNISINOS
ESTRUTURAS AVANÇADAS DE DADOS
41
Download