Post on 15-Jan-2016
description
Árvores de Busca
2
Á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.
3
Binary Search Tree (BST)
Definição (Árvore de busca M-way)Uma árvore de busca M-way T é 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., k i<ki+1
para 1 i n-1 Todas as chaves contidas na sub árvore T i-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 T i são maiores do que ki. A árvore Ti+1 é chamada sub árvore da direita com respeito à chave ki.
4
Exemplo de árvore de busca M-Way
5
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: 1. Todas as chaves contidas na sub árvore da
esquerda, TL, são menores do que r. 2. Todas as chaves contidas na sub árvore da
direita, TR , são maiores do que r.
6
Exemplo de árvore binária de busca
7
Busca em Árvores de Busca M-Way
Busca do objeto x inicia na raizSe a raiz estiver vazia a busca falhaAs chaves contidas na raiz são examinadas para verificar se o objeto buscado está presenteSe 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
8
Busca em Árvores Binárias de Busca
Semelhante à busca em árvores de busca M-WayApenas cada nó só possui um objeto e duas sub árvores
9
Á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: 1. Se h=0, então TL = e TR = .
2. Caso contrário, h>0, caso no qual ambos TL e TR são Árvores Binárias Perfeitas de altura h -1.
Implementação Java
11
Implementação de Árvores de Busca
12
Interface SearchTree
// pgm10_01.javapublic interface SearchTree extends Tree, SearchableContainer{ Comparable findMin (); Comparable findMax ();}
13
Classe BinarySearchTree
// pgm10_02.java
public class BinarySearchTree
extends BinaryTree
implements SearchTree
{
// ...
}
14
Classe Association
public class Association extends AbstractObject{ protected Comparable key; protected Object value;
// ...}
// só aparece por causa de getKey
15
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; } // ...}
16
Métodos da Classe BinarySearchTree
getLeftBSTgetRightBSTfindfindMininsertattachKeybalancewithdraw
17
Métodos getLeftBST e getRightBST
// pgm10_03.javapublic class BinarySearchTree extends BinaryTree implements SearchTree{ private BinarySearchTree getLeftBST()
{ return (BinarySearchTree) getLeft(); } private BinarySearchTree getRightBST()
{ return (BinarySearchTree) getRight(); } // ...}
18
Método find// pgm10_04.javapublic 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);
}}
19
Método findMin
public Comparable findMin () {
if(isEmpty()) return null;
elseif(getLeftBST().isEmpty())
return (Comparable) getKey();else
return getLeftBST().findMin(); } // ...
20
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.
21
Método insert (1)
// pgm10_05.javapublic class BinarySearchTree extends BinaryTree implements SearchTree{ public void insert (Comparable object) {
if(isEmpty()) attachKey (object);
22
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);
elsegetRightBST().insert(object);
} balance();
}}
23
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() {}
24
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.
25
Remoção de itens em BST
Remoção do nó (4) folha em BST
Remoção do nó (1) não folha em BST
26
Método withdraw (1)// pgm10_06.javapublic 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);
}
27
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(); } // ...}
Árvores de Busca AVL
29
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 .
Implementação de árvores AVL
31
Classe AVLTree
// pgm10_07.java
public class AVLTree
extends BinarySearchTree
{
protected int Height;
// ...
}
32
Construtor
// pgm10_08.javapublic class AVLTree extends BinarySearchTree{ protected int Height;
public AVLTree() { Height = -1; }
// ...}
33
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();
}
34
Inserção de itens em Árvores AVL
1o. Passo – Inserir o item2o. Passo – Balancear a árvore
35
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)
36
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 direitaA 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
37
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.
38
Rotação Simples LL
39
Propriedades das rotações simples
Existem três propriedades importantes da rotação LL:
1. 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.
2. 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.
3. Após a rotação a árvore permanece com a altura original. A inclusão do item não aumenta a altura da árvore.
40
Rotações Duplas
41
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:
42
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 LL2o 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 RR3 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)
43
Rotação LL
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 Inicialmente (*ya).bal = +1 (*s).bal = 0 A rotação consiste em: s (*ya).left temporário (*s).right (*s).right ya (*ya).left temporário
44
Rotação LL
45
Rotação RR
2 o 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. Inicialmente (*ya).bal = -1 (*s).bal = 0 A rotação consiste em: s (*ya).right temporário ya (*s).left ya (*ya).right temporário
46
Rotação RR
47
Rotação LR
3 o caso: O novo é incluído na sub árvore esquerda da sub árvore direita do filho mais velho de ya. Inicialmente (*ya).bal = + 1 (*s).bal = 0 A rotação consiste em: s ya.left q (*s).right temporário (*q).left (*q).left s (*s).right temporário temporário (*q).right (*q).right ya (*ya).left temporário
48
Rotação LR
49
Rotações LR e RL
4 o caso: O novo nó é incluído na sub árvore direita da sub árvore direita do filho mais velho de ya. Inicialmente (*ya).bal = +1 (*s).bal = 0 A rotação é a mesma do caso anterior
5 o caso: O novo nó é incluído na sub árvore direita da sub árvore esquerda do filho mais novo de ya. Inicialmente (*ya).bal = -1 (*s).bal = 0 A rotação consiste em: s (*ya).right q (*s).left temporário (*q).right (*q).right s (*s).left temporário temporário (*q).left (*q).left ya (*ya).right temporário
50
Rotação LR
51
Rotação RL
52
Classe AVLTree
public class AVLTree
extends BinarySearchTree
{
protected int Height;
// ...
}
53
Métodos height, getHeight e getBalanceFactor (1)
public class AVLTree extends BinarySearchTree{ protected int height;
public AVLTree() { height = -1; }
public int getHeight() { return height; }
protected void adjustHeight() {
if(isEmpty()) height = -1;
else height = 1 + Math.max (left.getHeight(),
right.getHeight()); }
54
Métodos height, getHeight e getBalanceFactor (2)
protected int getBalanceFactor() {
if(isEmpty()) return 0;
else return left.getHeight() - right.getHeight();
} // ...}
55
Método doLLRotation (1)
// pgm10_09.javapublic class AVLTree extends BinarySearchTree{ protected int Height;
protected void doLLRotation() {
if(isEmpty()) throw new InvalidOperationException();
BinaryTree tmp = right; right = left; left = right.left; right.left = right.right; right.right = tmp;
56
Método doLLRotation (2)
Object tmpObj = key;key = right.key;right.key = tmpObj;
getRightAVL().adjustHeight();adjustHeight();
} // ...}
57
Método doRRRotation (1)
public class AVLTree extends BinarySearchTree{ protected int Height;
protected void doRRRotation() {
if(isEmpty()) throw new InvalidOperationException();
BinaryTree tmp = left; left = right; right = left.right; left.right = left.left; left.left = tmp;
58
Método doRRRotation (2)
Object tmpObj = key;key = left.key;left.key = tmpObj;
getLeftAVL().adjustHeight();adjustHeight();
} // ...}
59
Método doLRRotation
// pgm10_10.javapublic class AVLTree extends BinarySearchTree{ protected int Height;
protected void doLRRotation() {
if(isEmpty()) throw new InvalidOperationException();
getLeftAVL().doRRRotation(); doLLRotation();
} // ...}
60
Método doRLRotation
public class AVLTree extends BinarySearchTree{ protected int Height;
protected void doRLRotation() {
if(isEmpty()) throw new InvalidOperationException();
getRightAVL().doLLRotation(); doRRRotation();
} // ...}
61
Método balance (1)
// pgm10_11.javapublic class AVLTree extends BinarySearchTree{ protected int Height;
protected void balance() {
adjustHeight(); if(getBalanceFactor() > 1) {
if(getLeftAVL().getBalanceFactor() > 0) doLLRotation();
else doLRRotation();
}
62
Método balance (2)
elseif(getBalanceFactor() < -1){
if(getRightAVL().getBalanceFactor() < 0)
doRRRotation(); else
doRLRotation();}
} // ...}
63
Método attachKey
// pgm10_12.javapublic class AVLTree extends BinarySearchTree{ protected int Height;
public void attachKey(Object object) {
if(!isEmpty()) throw new InvalidOperationException(); key = object; left = new AVLTree(); right = new AVLTree(); Height = 0;
} // ...}
Remoção de itens de Árvores AVL
65
Método detachKey
// pgm10_13.javapublic class AVLTree extends BinarySearchTree{ protected int Height;
public Object detachKey() {
Height = -1; return super.detachKey();
} // ...}
Árvores de Busca de Múltiplos caminhos
67
Implementação
68
Classe MwayTree: Métodos construtor e getM
// pgm10_14.javapublic class MWayTree extends AbstractTree implements SearchTree{ protected Comparable key[]; protected MWayTree subtree[]; public MWayTree(int m) {
if(m < 2) throw new IllegalArgumentException(“grau inválido");
key = new Comparable[m]; subtree = new MWayTree[m];
} int getM()
{ return subtree.length; } // ...}
69
Travessia em ordem infixa de árvores binárias de busca
Travessias infixas de árvores binárias são da forma: Percorrer a sub árvore da esquerda Visitar a raiz Percorre a sub árvore da direita
Isto corresponde a, em uma travessia infixa de uma árvore binária de busca, visitar a todos os registros armazenados na árvore em ordem
70
Travessia em ordem infixa
Travessias infixas não são definidas para árvores N-ariasEm árvores de busca M-Way a travessia infixa é definida como a visita a todos os registros armazenados na árvore em ordem
71
Travessia de um nó de uma árvore de busca M-Way
Percorrer a sub árvore T0
Visitar o objeto k1
Percorrer a sub árvore T1
Visitar o objeto k2
Percorrer a sub árvore T2
.
.
.Visitar o objeto kn-1
Percorrer a sub árvore Tn-1
72
Método depthFirstTraversal (1)
// pgm10_15.javapublic class MWayTree extends AbstractTree implements SearchTree{ protected Comparable key[]; protected MWayTree subtree[];
public void depthFirstTraversal (PrePostVisitor visitor) {
if(!isEmpty()) {
for(int i = 0; i <= count + 1; ++i) {
73
Método depthFirstTraversal (2)
if(i >= 2) visitor.postVisit(key[i - 1]);
if(i >= 1 && i <= count) visitor.inVisit(key[i]);
if(i <= count - 1) visitor.preVisit(key[i + 1]);
if(i <= count)
subtree[i].depthFirstTraversal(visitor); }
} } }
Busca linear de itens em Árvores M-Way
75
Método find (1)
// pgm10_16.javapublic class MWayTree extends AbstractTree implements SearchTree{ protected Comparable key[]; protected MWayTree subtree[];
public Comparable find(Comparable object) {
if(isEmpty()) return null;
int i;
76
Método find (2)
for(i = count; i > 0; --i) {
int diff = object.compare(key[i]); if(diff == 0)
return key[i]; if(diff > 0)
break; } return subtree[i].find(object);
} // ...}
Inclusão de itens
78
Método insert (1)
// pgm10_18.javapublic void insert (Comparable object){
if(isEmpty()) {
subtree[0] = new MWayTree(getM()); key[1] = object; subtree[1] = new MWayTree(getM()); count = 1; } else { int index = findIndex(object); if(index != 0 && object.isEQ(key[index]))
throw new IllegalArgumentException (“chave duplicada");
79
Método insert (2)
if(!isFull()) {
for(int i = count; i > index; --i) {
key[i + 1] = key[i]; subtree[i + 1] = subtree[i];
} key[index + 1] = object; subtree[index + 1] = new MWayTree(getM()); ++count;
} else
subtree[index].insert(object); }
}
Remoção de itens
81
Método withdraw (1)
public void withdraw (Comparable object){
if(isEmpty()) throw new IllegalArgumentException
("objeto não encontrado"); int index = findIndex(object); if(index != 0 && object.isEQ(key[index])) { if(!subtree[index - 1].isEmpty()) {
Comparable max = subtree[index - 1].findMax();
key[index] = max; subtree[index - 1].withdraw(max);
} else
82
Método withdraw (2)
if(!subtree[index].isEmpty()) {
Comparable min = subtree[index].findMin();
key[index] = min; subtree[index].withdraw(min);
} else {
--count; int i; for(i = index; i <= count; ++i) { key[i] = key[i + 1];
subtree[i] = subtree[i + 1]; }
83
Método withdraw (3)
key[i] = null; subtree[i] = null; if(count == 0)
subtree[0] = null; } } else subtree[index].withdraw(object);
}
Implementação C++
85
Implementação de Árvores de Busca
86
Definição da Classe SearchTree
// pgm10_01.cpp
class SearchTree :
public virtual Tree, public virtual SearchableContainer
{
public:
virtual Object& FindMin() const = 0;
virtual Object& FindMax() const = 0;
};
87
Definição da Classe BST
// pgm10_02.cpp
class BST : public BinaryTree, public SearchTree
{
protected:
virtual void AttachKey(Object&);
virtual Object& DetachKey();
virtual void Balance();
public:
BST& Left() const;
BST& Right() const;
// ...
};
88
Funções da Classe BinarySearchTree
leftrightfindfindMininsertattachKeywithdrawdetachKey
89
Definições da Função Membro Left e Rigth da Classe BST
// pgm10_03.cpp
BST& BST::Left() const
{ return dynamic_cast<BST&>(BinaryTree::Left ()); }
BST& BST::Right() const
{ return dynamic_cast<BST&>(BinaryTree::Right ()); }
90
Definições da Função Membro Find e FindMin da Classe BST (1)
// pgm10_04.cppObject& BST::Find(Object const& object) const{
if(IsEmpty ())return NullObject::Instance();
int const diff = object.Compare(*key);if(diff == 0)
return *key;else
if(diff < 0)return Left().Find(object);
elsereturn Right().Find(object);
}
91
Definições da Função Membro Find e FindMin da Classe BST (2)
Object& BST::FindMin() const{
if(IsEmpty ())return NullObject::Instance();
elseif(Left().IsEmpty())
return *key;else
return Left().FindMin();}
92
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.
93
Definições da Função Membro Insert, AttachKey e Balance da Classe BST (1)
// pgm10 {_05.cppvoid BST::Insert(Object& object){
if(IsEmpty ())AttachKey(object);
elseint const diff = object.Compare(*key);if(diff == 0)
throw invalid_argument(“chave duplicada");
if(diff < 0)Left().Insert(object);
elseRight().Insert(object);
}Balance();
}
94
Definições da Função Membro Insert, AttachKey e Balance da Classe BST (2)
void BST::AttachKey(Object& object){
if(!IsEmpty ())throw domain_error("operação inválida");
key = &object;left = new BST();right = new BST();
}void BST::Balance()
{}
95
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.
96
Remoção de itens em BST
Remoção do nó (4) folha em BST
Remoção do nó (1) não folha em BST
97
Definições da Função Membro Withdraw e DetachKey da Classe BST (1)
// pgm10_06.cppvoid BST::Withdraw(Object& object){
if(IsEmpty ())throw invalid_argument("objeto não
encontrado");int const diff = object.Compare(*key);if(diff == 0){
if(!Left().IsEmpty()){
Object& max = Left().FindMax();key = &max;Left().Withdraw(max);
}
98
Definições da Função Membro Withdraw e DetachKey da Classe BST (2)
elseif(!Right().IsEmpty()){Object& min = Right().FindMin();key = &min;Right().Withdraw(min);}elseDetachKey();}elseif(diff < 0)Left().Withdraw(object);elseRight().Withdraw(object);Balance();
}
99
Definições da Função Membro Withdraw e DetachKey da Classe BST (3)
Object& BST::DetachKey(){
if(!IsLeaf ())throw domain_error("operação inválida");
Object& result = *key;delete left;delete right;key = 0;left = 0;right = 0;return result;
}
Implementação de árvores AVL
101
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 .
Implementação de árvores AVL
103
Definição da Classe AVLTree (1)
// pgm10_07.cppclass AVLTree : public BST{protected:
int height;int BalanceFactor() const;void AdjustHeight();void LLRotation();void LRRotation();void RRRotation();void RLRotation();void AttachKey(Object&);Object& DetachKey();void Balance();
104
Definição da Classe AVLTree (2)
public:
AVLTree();
int Height() const;
AVLTree& Left() const;
AVLTree& Right() const;
};
105
Definições da Função Membro Height, AdjustHeight e BalanceFactor e do Construtor da Classe AVLTree (1)
// pgm10_08.cppAVLTree::AVLTree() :
BST(),height(-1){}
int AVLTree::Height() const{ return height; }
void AVLTree::AdjustHeight(){
if(IsEmpty ())height = -1;
elseheight = Max(left->Height(), right->Height())
+ 1;}
106
Definições da Função Membro Height, AdjustHeight e BalanceFactor e do Construtor da Classe AVLTree (2)
int AVLTree::BalanceFactor() const
{
if(IsEmpty ())
return 0;
else
return left->Height() - right->Height();
}
107
Definição da Função Membro LLRotation da Classe AVLTree// pgm10_09.cppvoid AVLTree::LLRotation(){
if(IsEmpty ())throw domain_error(“rotação inválida");
BinaryTree* const tmp = right;right = left;left = Right().left;Right().left = Right().right;Right().right = tmp;Object* const tmpObj = key;key = Right().key;Right().key = tmpObj;Right().AdjustHeight();AdjustHeight();
}
108
Definição da Função Membro LRRotation da Classe AVLTree
// pgm10_10.cpp
void AVLTree::LRRotation()
{
if(IsEmpty ())
throw domain_error("rotação inválida");Left().RRRotation();
LLRotation();
}
109
Definição da Função Membro Balance da Classe AVLTree
// pgm10_11.cppvoid AVLTree::Balance() {
AdjustHeight();if(abs(BalanceFactor ()) > 1) {
if(BalanceFactor() > 0) {if(Left().BalanceFactor() > 0)
LLRotation();else
LRRotation();}else {
if(Right().BalanceFactor() < 0)RRRotation();
elseRLRotation();
}}
}
110
Definições das Função Membro AttachKey e DetachKey da Classe AVLTree
// pgm10_12.cpp
void AVLTree::AttachKey(Object& object)
{
if(!IsEmpty ())
throw domain_error("operação inválida");
key = &object;
left = new AVLTree();
right = new AVLTree();
height = 0;
}
Object& AVLTree::DetachKey()
{ height = -1; return BST::DetachKey (); }
111
Definição da Classe MWayTree
// pgm10_13.cppclass MWayTree : public SearchTree{protected:
unsigned int const m;unsigned int numberOfKeys;Array<Object*> key;Array<MWayTree*> subtree;unsigned int FindIndex(Object const&) const;
public:MWayTree(unsigned int);~MWayTree();Object& Key(unsigned int) const;MWayTree& Subtree(unsigned int) const;// ...
};
112
Definição da Função Membro DepthFirstTraversal da Classe MWayTree
// pgm10_14.cppvoid MWayTree::DepthFirstTraversal( PrePostVisitor& visitor) const{
if(!IsEmpty ()){
for(int i = 0; i <= numberOfKeys + 1; ++i){
if(i >= 2)visitor.PostVisit(*key [i - 1]);
if(i >= 1 && i <= numberOfKeys)visitor.Visit(*key [i]);
if(i <= numberOfKeys - 1)visitor.PreVisit(*key [i + 1]);
if(i <= count)subtree[i]->DepthFirstTraversal (visitor);
}}
}
113
Definição (Linear Search) da Função Membro Find da Classe MWayTree// pgm10_15.cppObject& MWayTree::Find(Object const& object) const{
if(IsEmpty ())return NullObject::Instance();
unsigned int i = numberOfKeys;while(i > 0){
int const diff = object.Compare(*key[i]);if(diff == 0)
return *key[i];if(diff > 0)
break;--i;
}return subtree[i]->Find(object);
}
114
Definições (Binary Search) da Função FindIndex e Find da Classe MWayTree (1)
// pgm10_16.cppunsigned int MWayTree::FindIndex(Object const& object) const{
if(IsEmpty ())throw domain_error("operação inválida");
if(object < *key[1])return 0;
unsigned int left = 1;unsigned int right = numberOfKeys;while(left < right) {
int const middle = (left + right + 1) / 2;if(object >= *key[middle])
left = middle;else
right = middle - 1U;}return left;
}
115
Definições (Binary Search) da Função FindIndex e Find da Classe MWayTree (2)
Object& MWayTree::Find(Object const& object) const{
if(IsEmpty ())return NullObject::Instance();
unsigned int const index = FindIndex(object);if(index != 0 && object == *key[index])
return *key[index];else
return subtree[index]->Find(object);}
116
Definição da Função Membro Insert da Classe MWayTree (1)
// pgm10_17.cppvoid MWayTree::Insert(Object& object){
if(IsEmpty ()){
subtree[0] = new MWayTree(m);key[1] = &object;subtree[1] = new MWayTree(m);numberOfKeys = 1;
}else{
unsigned int const index = FindIndex(object);if(index != 0 && object == *key[index])
throw invalid_argument(“chave duplicada");
if(numberOfKeys < m - 1U){
117
Definição da Função Membro Insert da Classe MWayTree (2)
for(unsigned int i = numberOfKeys; i > index; --i)
{
key[i + 1] = key[i];
subtree[i + 1] = subtree[i];
}
key[index + 1] = &object;
subtree[index + 1] = new MWayTree(m);
++numberOfKeys;
}
else
subtree[index]->Insert(object);
}
}
118
Definição da Função Membro Withdraw da Classe MWayTree (1)
// pgm10_18.cppvoid MWayTree::Withdraw(Object& object){
if(IsEmpty ())throw invalid_argument("objeto não encontrado");
unsigned int const index = FindIndex(object);if(index != 0 && object == *key[index]){
if(!subtree[index - 1U]->IsEmpty()){
Object& max = subtree[index - 1U]->FindMax();
key[index] = &max;subtree[index - 1U]->Withdraw(max);
}
119
Definição da Função Membro Withdraw da Classe MWayTree (2)
elseif(!subtree[index]->IsEmpty()){
Object& min = subtree[index]->FindMin();key[index] = &min;subtree[index]->Withdraw(min);
}else{
--numberOfKeys;delete subtree[index];for(unsigned int i = index; i <= numberOfKeys; ++i){
key[i] = key[i + 1];subtree[i] = subtree[i + 1];
}
120
Definição da Função Membro Withdraw da Classe MWayTree (3)
if(numberOfKeys == 0)delete subtree[0];
}}else subtree[index]->Withdraw(object);
}
121
Definição da Classe BTree
// pgm10_19.cppclass BTree : public MWayTree{
BTree* parent;void InsertPair(Object&, BTree&);void AttachKey(unsigned int, Object&);void AttachSubtree(unsigned int, MWayTree&);Object& InsertKey(unsigned int, Object&);BTree& InsertSubtree(unsigned int, BTree&);void AttachLeftHalfOf(BTree const&);void AttachRightHalfOf(BTree const&, Object&, BTree&);
public:BTree(unsigned int);BTree(unsigned int, BTree&);void Insert(Object&);void Withdraw(Object&);
};
122
Definição da Função Membro Insert da Classe BTree (1)
// pgm10_20.cppvoid BTree::Insert(Object& object){
if(IsEmpty ()){
if(parent == 0){
AttachSubtree(0, *new BTree(m, *this));AttachKey(1, object);AttachSubtree(1, *new BTree(m, *this));numberOfKeys = 1;
}else
parent->InsertPair(object, *new BTree(m, *parent));}
123
Definição da Função Membro Insert da Classe BTree (2)
else{
unsigned int const index = FindIndex(object);if(index != 0 && object == *key[index]) throw invalid_argument(“chave duplicada");subtree[index]->Insert(object);
}}
124
Definição da Função Membro InsertPair da Classe BTree (1)
// pgm10_21.cppvoid BTree::InsertPair(Object& object, BTree& child){
unsigned int const index = FindIndex(object);BTree& extraTree = InsertSubtree(index + 1, child);Object& extraKey = InsertKey(index + 1, object);if(++numberOfKeys == m){
if(parent == 0){
BTree& left = *new BTree(m, *this);BTree& right = *new BTree(m, *this);left.AttachLeftHalfOf(*this);
125
Definição da Função Membro InsertPair da Classe BTree (2)
right.AttachRightHalfOf(*this, extraKey, extraTree);
AttachSubtree(0, left);AttachKey(1, *key[(m + 1)/2]);AttachSubtree(1, right);numberOfKeys = 1;
}else{
numberOfKeys =(m + 1) / 2 - 1;BTree& right = *new BTree(m, *parent);right.AttachRightHalfOf(*this, extraKey,
extraTree);parent->InsertPair(*key[(m + 1)/2], right);
}}
}