Árvores de Busca

Download Report

Transcript Árvores de Busca

Árvores de Busca
Á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.
2
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., ki<ki+1
para 1  i  n-1
 Todas as chaves contidas na sub árvore Ti-1 são menores do
que ki. A árvore Ti-1 é chamada sub árvore da esquerda com
respeito à chave ki.
 Todas as chaves contidas na sub árvore Ti são maiores do
que ki. A árvore Ti+1 é chamada sub árvore da direita com
respeito à chave ki.
3
Exemplo de árvore de busca M-Way
4
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.
5
Exemplo de árvore binária de busca
6
Busca em Árvores de Busca M-Way
Busca do objeto x inicia na raiz
Se a raiz estiver vazia a busca falha
As chaves contidas na raiz são examinadas para
verificar se o objeto buscado está presente
Se o objeto não estiver presente três casos podem
ocorrer:
 Objeto buscado é menor do que k1
 a busca prossegue em T0;
 Objeto buscado é maior do que kn-1
 a busca prossegue em Tn-1;
 Existe um i tal que ki < x < ki+1
 a busca prossegue em Ti
7
Busca em Árvores Binárias de Busca
Semelhante à busca em árvores de
busca M-Way
Apenas cada nó só possui um objeto e
duas sub árvores
8
Á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.
9
Implementação Java
Implementação de Árvores de Busca
11
Interface SearchTree
// pgm10_01.java
public interface SearchTree
extends Tree, SearchableContainer
{
Comparable findMin ();
Comparable findMax ();
}
12
Classe BinarySearchTree
// pgm10_02.java
public class BinarySearchTree
extends BinaryTree
implements SearchTree
{
// ...
}
13
Classe Association
public class Association
extends AbstractObject
{
protected Comparable key;
protected Object value;
// ...
}
// só aparece por causa de getKey
14
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; }
// ...
}
15
Métodos da Classe BinarySearchTree
getLeftBST
getRightBST
find
findMin
insert
attachKey
balance
withdraw
16
Métodos getLeftBST e getRightBST
// pgm10_03.java
public class BinarySearchTree
extends BinaryTree
implements SearchTree
{
private BinarySearchTree getLeftBST()
{ return (BinarySearchTree) getLeft(); }
private BinarySearchTree getRightBST()
{ return (BinarySearchTree) getRight(); }
// ...
}
17
Método find
// pgm10_04.java
public class BinarySearchTree
extends BinaryTree
implements SearchTree
{
public Comparable find (Comparable object)
{
if(isEmpty())
return null;
int diff = object.compare((Comparable) getKey());
if(diff == 0)
return (Comparable) getKey();
else
if(diff < 0)
return getLeftBST().find(object);
else
return getRightBST().find(object);
}
18
}
Método findMin
public Comparable findMin ()
{
if(isEmpty())
return null;
else
if(getLeftBST().isEmpty())
return (Comparable) getKey();
else
return getLeftBST().findMin();
}
// ...
19
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.
20
Método insert (1)
// pgm10_05.java
public class BinarySearchTree
extends BinaryTree
implements SearchTree
{
public void insert (Comparable object)
{
if(isEmpty())
attachKey (object);
21
Método insert (2)
else
{
int diff = object.compare((Comparable) getKey());
if(diff == 0)
throw new IllegalArgumentException(
“chave duplicada");
if(diff < 0)
getLeftBST().insert(object);
else
getRightBST().insert(object);
}
balance();
}
}
22
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()
{}
23
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.
24
Remoção de itens em BST
Remoção do nó (4) folha em BST
Remoção do nó (1) não folha em BST
25
Método withdraw (1)
// pgm10_06.java
public class BinarySearchTree
extends BinaryTree
implements SearchTree
{
public void withdraw (Comparable object)
{
if(isEmpty())
throw new IllegalArgumentException(
"objeto não encontrado")
int diff = object.compare ((Comparable) getKey());
if(diff == 0)
{
if(!getLeftBST().isEmpty())
{
Comparable max = getLeftBST().findMax();
key = max;
getLeftBST().withdraw(max);
}
26
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();
}
// ...
}
27
Árvores de Busca AVL
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 |hLhR|<=1
aonde hL é a altura of TL e hR é a altura of TR .
29
Implementação de árvores AVL
Classe AVLTree
// pgm10_07.java
public class AVLTree
extends BinarySearchTree
{
protected int Height;
// ...
}
31
Construtor
// pgm10_08.java
public class AVLTree
extends BinarySearchTree
{
protected int Height;
public AVLTree()
{ Height = -1; }
// ...
}
32
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();
}
33
Inserção de itens em Árvores AVL
1o. Passo – Inserir o item
2o. Passo – Balancear a árvore
34
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)
35
Rotações simples
A rotação LL ocorre quando um nó (B) tem a
sub árvore da esquerda maior do que a da
direita e seu filho da esquerda (A) tem sub
árvore da esquerda maior do que a da direita
A rotação RR ocorre quando um nó (B) tem a
sub árvore da direita maior do que a da
esquerda e seu filho da direita (A) tem sub
árvore da direita maior do que a da esquerda
36
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.
37
Rotação Simples LL
38
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.
39
Rotações Duplas
40
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:
41
Categorias de rotações
1o caso: O novo nó é incluído na sub árvore esquerda da sub
árvore esquerda do nó ya. Este caso tem solução chamada de
rightrotation ou rotação LL
2o caso: O novo nó é incluído na sub árvore direita da sub
árvore direita do nó ya. Este caso tem solução chamada de
leftrotation ou rotação RR
3 o caso: O novo é incluído na sub árvore esquerda da sub
árvore direita do filho mais velho de ya (rotação LR)
4 o caso: O novo nó é incluído na sub árvore direita da sub
árvore direita do filho mais velho de ya (LR)
5 o caso: O novo nó é incluído na sub árvore direita da sub
árvore esquerda do filho mais novo de ya (RL)
6 o caso: O novo nó incluído na sub árvore esquerda da sub
árvore esquerda do filho mais novo de ya (RL)
42
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
43
Rotação LL
44
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
45
Rotação RR
46
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
47
Rotação LR
48
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
49
Rotação LR
50
Rotação RL
6 o caso: O novo nó incluído na sub árvore esquerda
da sub árvore esquerda
do filho mais novo de ya.
Inicialmente
(*ya).bal = -1
(*s).bal = 0
A rotação é a mesma do caso anterior.
51
Classe AVLTree
public class AVLTree
extends BinarySearchTree
{
protected int Height;
// ...
}
52
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());
}
53
Métodos height, getHeight e
getBalanceFactor (2)
protected int getBalanceFactor()
{
if(isEmpty())
return 0;
else
return left.getHeight() - right.getHeight();
}
// ...
}
54
Método doLLRotation (1)
// pgm10_09.java
public 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;
55
Método doLLRotation (2)
Object tmpObj = key;
key = right.key;
right.key = tmpObj;
getRightAVL().adjustHeight();
adjustHeight();
}
// ...
}
56
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;
57
Método doRRRotation (2)
Object tmpObj = key;
key = left.key;
left.key = tmpObj;
getLeftAVL().adjustHeight();
adjustHeight();
}
// ...
}
58
Método doLRRotation
// pgm10_10.java
public class AVLTree
extends BinarySearchTree
{
protected int Height;
protected void doLRRotation()
{
if(isEmpty())
throw new InvalidOperationException();
getLeftAVL().doRRRotation();
doLLRotation();
}
// ...
}
59
Método doRLRotation
public class AVLTree
extends BinarySearchTree
{
protected int Height;
protected void doRLRotation()
{
if(isEmpty())
throw new InvalidOperationException();
getRightAVL().doLLRotation();
doRRRotation();
}
// ...
}
60
Método balance (1)
// pgm10_11.java
public class AVLTree
extends BinarySearchTree
{
protected int Height;
protected void balance()
{
adjustHeight();
if(getBalanceFactor() > 1)
{
if(getLeftAVL().getBalanceFactor() > 0)
doLLRotation();
else
doLRRotation();
}
61
Método balance (2)
else
if(getBalanceFactor() < -1)
{
if(getRightAVL().getBalanceFactor() < 0)
doRRRotation();
else
doRLRotation();
}
}
// ...
}
62
Método attachKey
// pgm10_12.java
public 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;
}
// ...
}
63
Remoção de itens de Árvores
AVL
Método detachKey
// pgm10_13.java
public class AVLTree
extends BinarySearchTree
{
protected int Height;
public Object detachKey()
{
Height = -1;
return super.detachKey();
}
// ...
}
65
Árvores de Busca de Múltiplos
caminhos
Implementação
67
Classe MwayTree: Métodos
construtor e getM
// pgm10_14.java
public 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; }
// ...
68
}
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
69
Travessia em ordem infixa
Travessias infixas não são definidas para
árvores N-arias
Em árvores de busca M-Way a travessia infixa
é definida como a visita a todos os registros
armazenados na árvore em ordem
70
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
71
Método depthFirstTraversal (1)
// pgm10_15.java
public 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)
{
72
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);
}
}
}
}
73
Busca linear de itens em Árvores
M-Way
Método find (1)
// pgm10_16.java
public class MWayTree
extends AbstractTree
implements SearchTree
{
protected Comparable key[];
protected MWayTree subtree[];
public Comparable find(Comparable object)
{
if(isEmpty())
return null;
int i;
75
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);
}
// ...
}
76
Inclusão de itens
Método insert (1)
// pgm10_18.java
public 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");
78
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);
}
}
79
Remoção de itens
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
81
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];
}
82
Método withdraw (3)
key[i] = null;
subtree[i] = null;
if(count == 0)
subtree[0] = null;
}
}
else
subtree[index].withdraw(object);
}
83
Implementação C++
Implementação de Árvores de Busca
85
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;
};
86
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;
// ...
};
87
Funções da Classe BinarySearchTree
left
right
find
findMin
insert
attachKey
withdraw
detachKey
88
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 ()); }
89
Definições da Função Membro Find e
FindMin da Classe BST (1)
// pgm10_04.cpp
Object& 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);
else
return Right().Find(object);
}
90
Definições da Função Membro Find e
FindMin da Classe BST (2)
Object& BST::FindMin() const
{
if(IsEmpty ())
return NullObject::Instance();
else
if(Left().IsEmpty())
return *key;
else
return Left().FindMin();
}
91
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.
92
Definições da Função Membro
Insert, AttachKey e Balance da
Classe BST (1)
// pgm10
{
_05.cpp
void BST::Insert(Object& object)
{
if(IsEmpty ())
AttachKey(object);
else
int const diff = object.Compare(*key);
if(diff == 0)
throw invalid_argument(“chave duplicada");
if(diff < 0)
Left().Insert(object);
else
Right().Insert(object);
}
Balance();
}
93
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()
{}
94
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.
95
Remoção de itens em BST
Remoção do nó (4) folha em BST
Remoção do nó (1) não folha em BST
96
Definições da Função Membro
Withdraw e DetachKey da Classe
BST (1)
// pgm10_06.cpp
void 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);
}
97
Definições da Função Membro
Withdraw e DetachKey da Classe
BST (2)
else
if(!Right().IsEmpty())
{
Object& min = Right().FindMin();
key = &min;
Right().Withdraw(min);
}
else
DetachKey();
}
else
if(diff < 0)
Left().Withdraw(object);
else
Right().Withdraw(object);
Balance();
}
98
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;
}
99
Implementação de árvores AVL
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 |hLhR|<=1
aonde hL é a altura of TL e hR é a altura of TR .
101
Implementação de árvores AVL
Definição da Classe AVLTree (1)
// pgm10_07.cpp
class 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();
103
Definição da Classe AVLTree (2)
public:
AVLTree();
int Height() const;
AVLTree& Left() const;
AVLTree& Right() const;
};
104
Definições da Função Membro Height,
AdjustHeight e BalanceFactor e do
Construtor da Classe AVLTree (1)
// pgm10_08.cpp
AVLTree::AVLTree() :
BST(),
height(-1)
{}
int AVLTree::Height() const
{ return height; }
void AVLTree::AdjustHeight()
{
if(IsEmpty ())
height = -1;
else
height = Max(left->Height(), right->Height()) +
1;
}
105
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();
}
106
Definição da Função Membro
LLRotation da Classe AVLTree
// pgm10_09.cpp
void 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();
}
107
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();
}
108
Definição da Função Membro
Balance da Classe AVLTree
// pgm10_11.cpp
void AVLTree::Balance() {
AdjustHeight();
if(abs(BalanceFactor ()) > 1) {
if(BalanceFactor() > 0) {
if(Left().BalanceFactor() > 0)
LLRotation();
else
LRRotation();
}
else {
if(Right().BalanceFactor() < 0)
RRRotation();
else
RLRotation();
}
}
}
109
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 (); }
110
Definição da Classe MWayTree
// pgm10_13.cpp
class 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;
// ...
};
111
Definição da Função Membro
DepthFirstTraversal da Classe
MWayTree
// pgm10_14.cpp
void 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);
}
}
112
}
Definição (Linear Search) da Função
Membro Find da Classe MWayTree
// pgm10_15.cpp
Object& 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);
}
113
Definições (Binary Search) da
Função FindIndex e Find da Classe
MWayTree (1)
// pgm10_16.cpp
unsigned 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;
114
}
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);
}
115
Definição da Função Membro Insert
da Classe MWayTree (1)
// pgm10_17.cpp
void 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)
{
116
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);
}
}
117
Definição da Função Membro
Withdraw da Classe MWayTree (1)
// pgm10_18.cpp
void 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);
}
118
Definição da Função Membro
Withdraw da Classe MWayTree (2)
else
if(!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];
}
119
Definição da Função Membro
Withdraw da Classe MWayTree (3)
if(numberOfKeys == 0)
delete subtree[0];
}
}
else subtree[index]->Withdraw(object);
}
120
Definição da Classe BTree
// pgm10_19.cpp
class 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&);
};
121
Definição da Função Membro Insert
da Classe BTree (1)
// pgm10_20.cpp
void 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));
}
122
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);
}
}
123
Definição da Função Membro
InsertPair da Classe BTree (1)
// pgm10_21.cpp
void 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);
124
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);
}
}
}
125