Árvores B
Implementação pelos FrameWork
Bruno Preiss
Árvores B
FrameWork Java de Bruno Preiss
Framework de Árvores e Busca
3
Interface Comparable
//pgm05_01.txt
public interface Comparable
{
boolean isLT (Comparable object);
boolean isLE (Comparable object);
boolean isGT (Comparable object);
boolean isGE (Comparable object);
boolean isEQ (Comparable object);
boolean isNE (Comparable object);
int compare (Comparable object);
}
4
Declaração da classe AbstractObject
//
pgm05_02.txt
public abstract class AbstractObject
implements Comparable
{
public final boolean isLT (Comparable object)
{ return compare (object) < 0; }
public final boolean isLE (Comparable object)
{ return compare (object) <= 0; }
public final boolean isGT (Comparable object)
{ return compare (object) > 0; }
public final boolean isGE (Comparable object)
{ return compare (object) >= 0; }
public final boolean isEQ (Comparable object)
{ return compare (object) == 0; }
public final boolean isNE (Comparable object)
{ return compare (object) != 0; }
public final boolean equals (Object object)
{
if (object instanceof Comparable)
return isEQ ((Comparable) object);
else
return false;
}
5
Métodos compareTo e compare
da classe AbstractObject
//pgm05_03.txt
//
public abstract class AbstractObject
implements Comparable
{
protected abstract int compareTo (Comparable arg);
public final int compare (Comparable arg)
{
if (getClass () == arg.getClass ())
return compareTo (arg);
else
return getClass ().getName ().compareTo (
arg.getClass ().getName ());
}
// ...
}
6
Interface Container
public interface Container
extends Comparable
{
int getCount ();
boolean isEmpty ();
boolean isFull ();
void purge ();
void accept (Visitor visitor);
Enumeration getEnumeration ();
}
7
Interface SearchableContainer
public interface SearchableContainer
extends Container
{
boolean isMember (Comparable object);
void insert (Comparable object);
void withdraw (Comparable obj);
Comparable find (Comparable object);
}
8
Interface Tree
//pgm09_01.txt
public interface Tree
extends Container
{
Object getKey ();
Tree getSubtree (int i);
boolean isEmpty ();
boolean isLeaf ();
int getDegree ();
int getHeight ();
void depthFirstTraversal (PrePostVisitor visitor);
void breadthFirstTraversal (Visitor visitor);
}
9
Interface SearchTree
//pgm10_01.txt
public interface SearchTree
extends Tree,
SearchableContainer
{
Comparable findMin ();
Comparable findMax ();
}
10
Classe Abstrata AbstractContainer
public abstract class AbstractContainer
extends AbstractObject
implements Container
{
protected int count;
public int getCount ()
{ return count; }
public boolean isEmpty ()
{ return getCount () == 0; }
public boolean isFull ()
{ return false; }
// ...
}
11
Classe Abstrata AbstractTree
//
pgm09_02.txt
public abstract class AbstractTree
extends AbstractContainer
implements Tree
{
public void depthFirstTraversal (PrePostVisitor
visitor)
{
if (visitor.isDone ())
return;
if (!isEmpty ())
{
visitor.preVisit (getKey ());
for (int i = 0; i < getDegree (); ++i)
getSubtree (i).depthFirstTraversal (visitor);
visitor.postVisit (getKey ());
}
}
// ...
}
12
Árvores MWay
13
Classe MwayTree: Métodos construtor e getM
//pgm10_14.txt
public class MWayTree
extends AbstractTree
implements SearchTree
{
protected Comparable key[];
protected MWayTree subtree[];
public MWayTree (int m)
{
if (m < 2)
throw new IllegalArgumentException("invalid degree");
key = new Comparable [m];
subtree = new MWayTree [m];
}
int getM ()
{ return subtree.length; }
// ...
}
14
Método find
Recebe um objeto e localiza o item na
árvore de busca que coincide com o objeto
buscado
Caso o objeto buscado não exista retorna
null
15
Método find da Classe MWayTree
//pgm10_16.txt
public class MWayTree
extends AbstractTree
implements SearchTree
{
protected Comparable key[];
protected MWayTree subtree[];
public Comparable find (Comparable object)
{
if (isEmpty ())
return null;
int i;
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);
}
}
16
Método findIndex
Recebe um objeto x e retorna i que é o
maior valor tal que x ≥ ki, sendo ki a chave
de ordem i no nó
17
Método findIndex da Classe MWayTree
//pgm10_17.txt
public class MWayTree
extends AbstractTree
implements SearchTree
{
protected Comparable key[];
protected MWayTree subtree[];
protected int findIndex (Comparable object)
{
if (isEmpty () || object.isLT (key [1]))
return 0;
int left = 1;
int right = count;
while (left < right)
{
int middle = (left + right + 1) / 2;
if (object.isLT (key [middle]))
right = middle - 1;
else
left = middle;
}
return left;
}
18
Classe BTree
//
pgm10_20.txt
public class BTree
extends MWayTree
{
protected BTree parent;
public BTree (int m)
{ super (m); }
public void attachSubtree (int i, MWayTree arg)
{
BTree btree = (BTree) arg;
subtree [i] = btree;
btree.parent = this;
}
// ...
}
19
Método insert da Classe BTree
Insere uma chave em uma página de árvore B
Se a página está vazia então:


Se a página não tem ancestral a chave será key[1] e a
página passará a ter duas filhas vazias
Caso contrário inserir no ancestral o par (chave, árvore B
vazia) pelo método insertPair
Se a página não estiver vazia:



Faz-se a busca do local apropriado calculando index pelo
método findIndex
Se o objeto for encontrado é lançada a exceção de chave
duplicada
O método chama a si mesmo recursivamente da forma
subtree [index].insert (object)
20
Método insert da Classe BTree
//
pgm10_21.txt
public void insert (Comparable object)
{
if (isEmpty ())
{
if (parent == null)
{
attachSubtree (0, new BTree (getM ()));
key [1] = object;
attachSubtree (1, new BTree (getM ()));
count = 1;
}
else
parent.insertPair (object, new BTree (getM ()));
}
else
{
int index = findIndex (object);
if (index != 0 && object.isEQ (key [index]))
throw new IllegalArgumentException (
"duplicate key");
subtree [index].insert (object);
}
}
21
Método insertPair da Clase BTree (1)
Inclui em um nó de árvore B um par (object, child)
Inicia buscando a posição correta na página com findIndex
Caso a página não esteja cheia:


O método insertKey é chamado para inserir a chave (object) na posição
correta do array de chaves
O método insertSubtree é chamado para inserir a árvore (child) na
correta posição do array de sub árvores
Caso a página esteja cheia:


O método insertKey retorna a chave que transborda do array de chaves
(maior valor) e que é atribuída a extraKey
O método insertSubtree retorna a sub árvore que sobra à direita do
array de sub árvores e que é atribuída a extraTree
22
Método insertPair da Clase BTree (2)
A página transbordou e é preciso balancear a árvore
Se o nó for a raiz:







Criam-se dois nós left e right
Left recebe as primeiras
chaves e primeiras
sub árvores pelo método attachLeftHalfOf
Right recebe as últimas
chaves a as últimas
sub árvores pelo método attachRightHalfOf
O par (extraKey,extraTree) é incluído no nó right
Left será a sub árvore 0 ligada à raiz por AttachSubtree
Right será a sub árvore 1 ligada à raiz por AttachSubtree
A chave que sobrou,
, é inserida na raiz modificada que terá
por folhas as página left e right
23
Método insertPair da Clase BTree (3)
Se o nó não for a raiz:






Cria-se um novo nó e right
Right recebe as últimas
chaves a as últimas
sub árvores pelo método attachRightHalfOf
O par (extraKey,extraTree) é incluído no nó right
As primeiras chaves e primeiras sub árvores permanecem no
nó corrente
A chave que sobrou é
O método chama a si mesmo, recursivamente, para inserir no
ancestral o par (chave que sobrou, right)
24
Método insertPair da Clase Btree (1)
protected void insertPair (Comparable object, BTree child)
{
int index = findIndex (object);
if (!isFull ())
{
insertKey (index + 1, object);
insertSubtree (index + 1, child);
++count;
}
else
{
Comparable extraKey = insertKey (index + 1, object);
BTree extraTree = insertSubtree (index + 1, child);
if (parent == null)
{
BTree left = new BTree (getM ());
BTree right = new BTree (getM ());
left.attachLeftHalfOf (this);
right.attachRightHalfOf (this);
right.insertPair (extraKey, extraTree);
attachSubtree (0, left);
key [1] = key [(getM () + 1)/2];
attachSubtree (1, right);
count = 1;
25
Método insertPair da Clase Btree (2)
else
{
count = (getM () + 1)/2 - 1;
BTree right = new BTree (getM ());
right.attachRightHalfOf (this);
right.insertPair (extraKey, extraTree);
parent.insertPair (key [(getM () + 1)/2], right);
}
}
}
26
Método attachSubtree
Recebe um inteiro i e uma árvore B
A árvore B recebida torna-se a sub árvore
de ordem i do nó corrente
27
Método attachSubtree
public void attachSubtree
(int i, MWayTree arg)
{
BTree btree = (BTree) arg;
subtree [i] = btree;
btree.parent = this;
}
28
Metodo attachLeftHalfOf
protected void attachLeftHalfOf (BTree tree) throws
IllegalArgumentException
{
attachSubtree (0, tree.subtree [0]);
count = 0;
for (int ind = 1;
ind < Math.ceil (((float) tree.getM ()) / 2);
++ind)
{
this.insertPair (tree.key [ind],
(BTree) tree.subtree [ind]);
}
}
29
Metodo attachRightHalfOf
protected void attachRightHalfOf (BTree tree) throws
IllegalArgumentException
{
attachSubtree (0, tree.subtree [(getM () + 1) / 2]);
count = 0;
for (int ind = getM () - 1;
ind > Math.ceil ((tree.getM () + 1) / 2);
--ind)
{
this.insertPair (tree.key [ind],
(BTree) tree.subtree [ind]);
}
}
30
Método insertSubtree
Recebe um inteiro índice e uma sub árvore e deve
inserir na correta posição do array de sub árvores
Caso a página não esteja cheia:
 A inserção é feita usando AttachSubtree e o
método retorna null
 As sub árvores “acima” do índice são
rearrumadas
Caso a página esteja cheia:

O método insertSubtree retorna a sub árvore que sobra
à direita do array de sub árvores e que é atribuída a
extraTree
31
Método insertSubtree (1)
private BTree insertSubtree (int index, BTree child)
{
BTree extraTree = null;
if (isFull ())
{
if (index == getM ())
extraTree = child;
else
{
extraTree = (BTree) subtree [count];
for (int i = count - 1; i >= index; --i)
{
subtree [i + 1] = subtree [i];
}
attachSubtree (index, child);
}
}
32
Método insertSubtree (2)
else
{
child.parent = this;
for (int i = count; i >= index; --i)
{
subtree [i + 1] = subtree [i];
}
subtree [index] = child;
}
return extraTree;
}
33
Método insertKey
Recebe um inteiro índice e um objeto e deve
inserir na correta posição do array de chaves
Caso a página não esteja cheia:


A inserção é feita e o método retorna null
As chaves “acima” do índice são rearrumadas
Caso a página esteja cheia:

O método insertKey retorna a chave que transborda do
array (maior valor) e que é atribuída a extraKey
34
Método insertKey (1)
private Comparable insertKey (int index, Comparable
object)
{
Comparable extraKey = null;
if (isFull ())
{
if (index == getM ())
extraKey = object;
else
{
extraKey = key [count];
for (int i = count - 1; i >= index; --i)
{
key [i + 1] = key [i];
}
key [index] = object;
}
}
35
Método insertKey (2)
else
{
for (int i = count; i >= index; --i)
{
key [i + 1] = key [i];
} // for (int i = count; i > index; --i) {
key [index] = object;
}
return extraKey;
}
36
Método withdraw (1)
Remove um objeto da árvore
Se a árvore estiver vazia lança uma exceção
Determina a posição do objeto no nó pelo método
findIndex
Caso tenha encontrado o objeto a excluir em uma
página não folha procura seu antecessor ou
sucessor para gravar sobre o objeto a ser excluído
e trata de excluir o antecessor ou sucessor
37
Método withdraw (2)
Caso tenha encontrado o objeto a excluir em
folha:
Decrementa o contador de população
 Leva para a esquerda do array de objetos todos os
superiores ao index do objeto a excluir
 Leva para a esquerda do array de sub árvores todas
as sub árvores correspondentes
 Anula o objeto e a sub árvore a excluir

38
Método withdraw (3)
Caso não tenha encontrado o objeto a excluir por
estar entre dois objetos do nó chama a si mesmo
da forma
subtree[index].withdraw(object)
Se o contador tornar-se menor do que o mínimo:


Se a nó corrente tiver ancestral chama o método
balance
Se for raiz e tiver ficado vazia chama o método
TrimmRoot
39
Método withdraw (1)
public void withdraw (Comparable object) throws
IllegalArgumentException,
InvalidOperationException
{
if (isEmpty ())
throw new IllegalArgumentException ("object not found");
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 if (!subtree [index].isEmpty ())
{
Comparable min =
subtree [index].findMin ();
key [index] = min;
subtree [index].withdraw (min);
}
40
Método withdraw (2)
else
{
--count;
int i;
for (i = index; i <= count; ++i)
{
key [i] = key [i + 1];
subtree [i] = subtree [i + 1];
}
key [i] = null;
subtree [i] = null;
}
}
else
subtree [index].withdraw (object);
if (count < getMin ())
if (parent != null)
balance ();
else if (count == 0)
rootTrim ();
}
41
Métodos getMin e isFull
public int getMin ()
{
return ((getM () + 1) / 2) - 1;
}
public boolean isFull ()
{
return getM () - 1 == count;
}
42
Método balance
Equilibra uma página sub povoada
Determina a posição no pai
Obtém a população das irmãs esquerda e direita
Caso a população da esquerda seja maior do que o mínimo
executa uma rotação à esquerda
Senão se a população da direita for maior do que o mínimo
executa uma rotação à direita
Caso contrário todas as páginas envolvidas estão com
população mínima e então:


concatena com a esquerda
(parent.concatenation(parentIndex)) ou
concatena com a direita
(parent.concatenation(parentIndex + 1))
Existe um teste de lado pois existe o tratamento diferenciado
das páginas extremas que possuem irmãs fictícias com
população menor do que a população mínima
43
Método balance
public void balance () throws IllegalArgumentException,
InvalidOperationException
{
int parentIndex = parent.findIndex (this.key [1]);
int LeftSister = getCountLeftSister (parentIndex);
int RightSister = getCountRightSister (parentIndex);
if (LeftSister > getMin ())
{
parent.doLLRotation (parentIndex);
}
else if (RightSister > getMin ())
{
parent.doRRRotation (parentIndex);
}
else if (LeftSister >= RightSister)
{
parent.concatenation (parentIndex);
}
else
{
parent.concatenation (parentIndex + 1);
}
}
44
Método printTree
public void printTree (Visitor visitor, int espaços)
throws ContainerEmptyException
{
if (!isEmpty ())
{
for (int i = count + 1; i >= 0; --i)
{
if (i <= count)
{
((BTree) subtree [i]).printTree (visitor, espaços +
3);
}
if (i >= 1 && i <= count)
{
for (int o = espaços; o > 0; --o)
System.out.print (" ");
visitor.visit (key [i]);
}
}
}
else if (parent == null)
throw new ContainerEmptyException ("Arvore vazia!");
}
45
Método getCountLeftSister
Obtém a população da irmã esquerda
Se for a primeira página sua irmã da esquerda
(inexistente) recebe população menor do que o
mínimo
Caso contrário usa-se o método getCount
parent.subtree[index - 1].getCount()
46
Método getCountLeftSister
public int getCountLeftSister
(int index)
{
if (index == 0)
return getMin () - 1;
else
return parent.subtree
[index - 1].getCount ();
}
47
Método getCountRightSister
Obtém a população da irmã direita
Se for a última página sua irmã da direita
(inexistente) recebe população menor do que o
mínimo
Caso contrário usa-se o método getCount
parent.subtree[index + 1].getCount()
48
Método getCountRightSister
public int getCountRightSister
(int index)
{
if (index == this.parent.count)
return getMin () - 1;
else
return parent.subtree
[index + 1].getCount ();
}
49
Método doLLRotation
Determina a posição do último objeto da irmã
esquerda e a sub árvore correspondente
No nó corrente pelo método insertPair são
gravados key[index] e a sub árvore determinada
no item anterior
key[index] recebe o último objeto da irmã
esquerda
O último objeto da irmã esquerda e a sub árvore
correspondente são removidos pelo método
removePair
50
Método doLLRotation
protected void doLLRotation (int index) throws
InvalidOperationException,
IllegalArgumentException
{
if (isEmpty ())
throw new InvalidOperationException ("Operação inválida!");
Comparable tempKey;
BTree tempSubtree;
int ultimaPosiçao;
ultimaPosiçao = subtree [index - 1].getCount ();
tempKey = subtree [index - 1].key [ultimaPosiçao];
tempSubtree = (BTree) subtree [index - 1].subtree
[ultimaPosiçao];
((BTree) subtree [index]).insertPair (key [index],
tempSubtree);
key [index] = tempKey;
((BTree) subtree [index - 1]).removePair (ultimaPosiçao);
}
51
Método doRRRotation
Determina a posição do primeiro objeto da irmã
direita e a sub árvore correspondente
No nó corrente pelo método insertPair são
gravados key[index + 1] e a sub árvore
determinada no item anterior
key[index + 1] recebe o primeiro objeto da irmã
direita
O primeiro objeto da irmã direita e a sub árvore
correspondente são removidos pelo método
removePair
52
Método doRRRotation
protected void doRRRotation (int index) throws
InvalidOperationException,
IllegalArgumentException
{
if (isEmpty ())
throw new InvalidOperationException
("Operação inválida!");
BTree tempSubtree;
tempSubtree = (BTree) subtree [index + 1].subtree [0];
((BTree) subtree [index]).insertPair
(key [index + 1], tempSubtree);
key [index + 1] = subtree [index + 1].key [1];
subtree [index + 1].subtree [0] =
subtree [index + 1].subtree [1];
((BTree) subtree [index + 1]).removePair (1);
}
53
Método concatenation
Concatena a página filha corrente (que será desalocada) com
sua irmã esquerda
A chave separadora de nós (key [index]) e a sub árvore da
esquerda da página filha corrente são copiados para a irmã
esquerda pelo método insertPair
Todas as chaves e sub árvores correspondentes da página filha
corrente são copiados para a irmã esquerda pelo método
insertPair
Todas as chaves e sub árvores da página corrente (ancestral
das que sofreram concatenação) maiores do que key
[index], que perdeu levado para a filha esquerda, são
deslocados para a esquerda
A última chave e a última sub árvore da página corrente são
anuladas
54
Método concatenation
protected void concatenation (int index) throws
IllegalArgumentException
{
((BTree) subtree [index - 1]).insertPair (key [index],
(BTree) subtree [index].subtree [0]);
for (int i = 1; i <= subtree [index].getCount (); ++i)
{
((BTree) subtree [index - 1]).insertPair
(subtree [index].key [i], BTree) subtree
[index].subtree [i]);
}
int i;
--count;
for (i = index; i <= count; ++i)
{
key [i] = key [i + 1];
subtree [i] = subtree [i + 1];
}
key [i] = null;
subtree [i] = null;
}
55
Método rootTrim
protected void rootTrim ()
{
count = subtree [0].getCount ();
int i;
for (i = count; i > 0; --i)
{
key [i] = subtree [0].key [i];
subtree [i] = subtree [0].subtree [i];
((BTree) subtree [i]).parent = this;
}
subtree [i] = subtree [0].subtree [i];
((BTree) subtree [i]).parent = this;
}
56
Método removePair
Remove de uma página a chave key [index] e
a sub árvore correspondente
O contador de objetos é decrementado
Todas as chaves e sub árvores da página corrente
maiores do que key [index], que perdeu
levado para a filha esquerda, são deslocados para a
esquerda
A última chave e a última sub árvore da página
corrente são anuladas
57
Método removePair
public void removePair (int index)
{
int i;
--count;
for (i = index; i <= count; ++i)
{
key [i] = key [i + 1];
subtree [i] = subtree [i + 1];
}
key [i] = null;
subtree [i] = null;
}
58
Árvores B
FrameWork C++ de Bruno Preiss
Framework de Árvores e Busca
60
Árvores MWay
61
Declaração da Classe Object
//
pgm05_01.cpp
class Object
{
protected:
virtual int CompareTo (Object const&) const = 0;
public:
virtual ~Object ();
virtual bool IsNull () const;
virtual int Compare (Object const&) const;
virtual HashValue Hash () const = 0;
virtual void Put (ostream&) const = 0;
};
62
Declaração da Classe Container
//
pgm05_09.cpp
class Container : public virtual Object, public virtual
Ownership
{
protected:
unsigned int count;
Container ();
public:
virtual unsigned int Count () const;
virtual bool IsEmpty () const;
virtual bool IsFull () const;
virtual HashValue Hash () const;
virtual void Put (ostream&) const;
virtual Iterator& NewIterator () const;
virtual void Purge () = 0;
virtual void Accept (Visitor&) const = 0;
};
63
Declaração da Classe Ownership
//
pgm05_17.cpp
class Ownership
{
bool isOwner;
protected:
Ownership () : isOwner (true)
{}
Ownership (Ownership& arg) : isOwner (arg.isOwner)
{ arg.isOwner = false; }
public:
void AssertOwnership ()
{ isOwner = true; }
void RescindOwnership ()
{ isOwner = false; }
bool IsOwner () const
{ return isOwner; }
};
64
Declaração da Classe
SearchableContainer
//
pgm05_21.cpp
class SearchableContainer : public
virtual Container
{
public:
virtual bool IsMember (Object const&)
const = 0;
virtual void Insert (Object&) = 0;
virtual void Withdraw (Object&) = 0;
virtual Object& Find (Object const&)
const = 0;
};
65
Declaração da Classe Tree
//
pgm09_01.cpp
class Tree : public virtual Container
{
class Iter;
public:
virtual Object& Key () const = 0;
virtual Tree& Subtree (unsigned int) const = 0;
virtual bool IsEmpty () const = 0;
virtual bool IsLeaf () const = 0;
virtual unsigned int Degree () const = 0;
virtual int Height () const;
virtual void DepthFirstTraversal (PrePostVisitor&) const;
virtual void BreadthFirstTraversal (Visitor&) const;
void Accept (Visitor&) const;
};
66
Declaraçã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;
};
67
Classe MwayTree: Definição
//
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;
Object& Find (Object const& ) const;
int GetCount() { return numberOfKeys; }
};
68
Funções Membro Construtor e Destrutor
da Classe MWayTree
MWayTree::MWayTree (unsigned int n) : m(n)
{
key.SetLength(m);
subtree.SetLength(m);
}
MWayTree::~MWayTree ()
{
}
69
Funções Membro Subtree e Key da
Classe MWayTree
MWayTree& MWayTree::Subtree (unsigned int i)
const
{
return *subtree[m];
}
Object& MWayTree::Key(unsigned int i) const
{
return *key[m];
}
70
Método Find
Recebe uma referencia a um objeto e
localiza o item na árvore de busca que
coincide com o objeto buscado
Caso o objeto buscado não exista retorna
uma instancia de NullObject
71
Método Find da Classe MWayTree
sem uso de função FindIndex
//
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);
}
72
Método FindIndex
Recebe uma referencia a um objeto x e
retorna i que é o maior valor tal que x ≥ ki,
sendo ki a chave de ordem i no nó
73
Método FindIndex da Classe MWayTree
// pgm10_16.cpp
unsigned int MWayTree::FindIndex (Object const& object) const
{
if (IsEmpty ())
throw std::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;
74
}
Método Find da Classe MWayTree
com uso de função FindIndex
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);
}
75
Classe Btree (1)
//
pgm10_19.cpp
class BTree : public MWayTree
{
BTree* parent;
void InsertPair (Object&, BTree&);
void RemovePair(unsigned int index);
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&);
bool IsFull();
unsigned int GetMin ();
void Balance ();
void PrintTree (Visitor& visitor, int spaces);
unsigned int GetCountRightSister (unsigned int index);
unsigned int GetCountLeftSister (unsigned int index);
void RRRotation (unsigned int index);
void LLRotation (unsigned int index);
void TrimmRoot ();
virtual MWayTree& Subtree (unsigned int) const ;
virtual bool IsEmpty () const ;
virtual bool IsLeaf () const ;
virtual unsigned int Degree () const ;
76
Classe Btree (2)
Object& FindMin () const;
Object& FindMax () const;
Object& Key(unsigned int );
bool IsMember (Object const& obj) const { return (
Find(obj) != NullObject::Instance() ); };
int CompareTo (Object const&) const { return 0; };
HashValue Hash () const { return 0; };
void Put (std::ostream&) const {};
protected:
void Concatenation (int index);
public:
BTree (unsigned int);
BTree (unsigned int, BTree&);
void Insert (Object&);
void Withdraw (Object&);
};
77
Função Membro Construtor da
Classe BTree
BTree::BTree (unsigned int m,
BTree& ancestral) : MWayTree(m)
{
this->parent = &ancestral;
}
78
Método Insert da Classe Btree (1)
//
pgm10_20.cpp
void BTree::Insert (Object& object)
{
if (IsEmpty ())
// ponteiro aterrado (folha)
{
if (parent == 0) // nó sem pai (raiz)
{
AttachSubtree (0, *new BTree (m, *this));
// nova árvore é o filho 0
AttachKey (1, object);
// objeto a inserir é a chave 1
AttachSubtree (1, *new BTree (m, *this));
// nova árvore é o filho 1
numberOfKeys = 1;
}
79
Método Insert da Classe Btree (2)
else
// folha com pai
// inserir no ancestral o objeto e árvore filho m
parent->InsertPair (object,
*new BTree (m, *parent));
}
else
// não estamos em folha
{
unsigned int const index = FindIndex (object);
// index é, no nó,a posição “abaixo” de object
if (index != 0 && object == *key [index])
throw std::domain_error (“chave duplicada");
subtree [index]->Insert (object);
// inserir o objeto na sub árvore adequada
}
}
80
Método InsertPair da Clase Btree (1)
//
pgm10_21.cpp
void BTree::InsertPair (Object& object, BTree& child)
{
unsigned int const index = FindIndex (object);
// posição da inserção
BTree& extraTree = InsertSubtree (index + 1,
child);
// insere sub árvore à direita de index
Object& extraKey = InsertKey (index + 1, object);
// insere objeto à direita de index
81
Método InsertPair da Clase Btree (2)
if (++numberOfKeys == m) // nó transborda
{
if (parent == 0)
// era a raiz
{
BTree& left = *new BTree (m, *this);
// left é nó de ordem m filho do corrente
BTree& right = *new BTree (m, *this);
// right é nó de ordem m filho do corrente
left.AttachLeftHalfOf (*this);
// adicionar a left a metade esquerda do nó corrente
right.AttachRightHalfOf (*this, extraKey, extraTree);
// adicionar a right o par inserido e a metade direita
// do nó corrente
AttachSubtree (0, left);
AttachKey (1, *key [(m + 1)/2]);
AttachSubtree (1, right);
numberOfKeys = 1;
}
82
Método InsertPair da Clase Btree (3)
else // nó transborda mas tem ancestral
{
numberOfKeys = (m + 1)/2 - 1;
// nova população da página corrente
BTree& right = *new BTree (m, *parent);
// right nova página irmã direita
right.AttachRightHalfOf (*this, extraKey, extraTree);
// adicionar a right o par a inserir e a metade direita
// do nó corrente
parent->InsertPair (*key [(m + 1)/2], right);
// inserir no ancestral o par objeto do meio e
// a página right
}
}
}
83
Função Membro AttachSubtree
void BTree::AttachSubtree (unsigned
int i, MWayTree& child)
{
subtree [i] = &child;
((BTree&) child).parent == this;
}
84
Função Membro InsertSubtree (1)
BTree& BTree::InsertSubtree (unsigned int index, BTree& child)
{
//Esta função vai retornar null quando o nó não estiver cheio
// quando o nó estiver cheio retorna a sub árvore que transbordou
if (IsFull ())
{
if (index == m)
// a sub árvore a inserir era maior do que as demais e vai sobrar
return child;
else
{
// vai sobrar a sub árvore que era a maior de todas
BTree& extraTree = (BTree&) *subtree [numberOfKeys];
for (int i = numberOfKeys - 1; i >= index; --i)
{
subtree[i + 1] = subtree[i];
}
AttachSubtree(index, child);
return extraTree;
}
}
85
Função Membro InsertSubtree (2)
else // nó com espaço
{
child.parent = this;
for (int i = numberOfKeys; i >= index;
--i)
{
subtree [i + 1] = subtree [i];
}
subtree [index] = &child;
}
return (BTree&) NullObject::Instance();
}
86
Função Membro InsertKey (1)
Object& BTree::InsertKey (unsigned int index, Object& object)
{
//Esta função vai retornar null quando o nó não
estiver cheio
// quando o nó estiver cheio retorna a chave que
transbordou
if (IsFull ())
{
if (index == m)
// a chave a inserir era maior do que as demais e
vai sobrar
return object;
else
{
// vai sobrar a chave que era a maior de todas
Object& extraKey = *key [numberOfKeys];
for (int i = numberOfKeys - 1; i >= index; --i)
{
key [i + 1] = key [i];
}
key [index] = &object;
return extraKey;
}
87
}
Função Membro InsertKey (2)
else // nó com espaço
{
for (int i = numberOfKeys; i >= index;
--i)
{
key [i + 1] = key [i];
}
key [index] = &object;
}
return NullObject::Instance ();
}
88
Função Membro Withdraw (1)
// pgm10_18.cpp
void MWayTree::Withdraw (Object& object)
{
if (IsEmpty ())
throw InvalidOperationException("objeto nao 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);
}
else if (!subtree [index]->IsEmpty ())
{
Object& min = subtree [index]->FindMin ();
key [index] = &min;
subtree [index]->Withdraw (min);
}
89
Função Membro Withdraw (2)
else
{
--numberOfKeys;
delete subtree [index];
for(unsigned int i = index; i <= numberOfKeys; ++i)
{
key [i] = key [i + 1];
subtree [i] = subtree [i + 1];
}
}
}
else
subtree [index]->Withdraw (object);
if (numberOfKeys < GetMin())
if (parent != 0)
Balance();
else if (numberOfKeys == 0)
RootTrim();
}
90
Função Membro FindMin
Object& BTree::FindMin () const
{
if (IsEmpty ())
return NullObject::Instance ();
else if (subtree[0]->IsEmpty ())
return *key[1];
else
return subtree[0]->FindMin();
}
91
Função Membro FindMax
Object& BTree::FindMax () const
{
if (IsEmpty ())
return NullObject::Instance ();
else if (subtree[numberOfKeys]->IsEmpty ())
return *key[numberOfKeys];
else
return subtree[numberOfKeys]->FindMax();
}
92
Função Membro GetMin e IsFull
unsigned int BTree::GetMin ()
{
return ((m + 1) / 2) - 1;
}
bool BTree::IsFull ()
{
return (m - 1) == numberOfKeys;
}
93
Função Membro Balance (1)
void BTree::Balance ()
{
int parentIndex = parent->FindIndex (this>key [1]);
int leftSister = GetCountLeftSister
(parentIndex);
int rightSister = GetCountRightSister
(parentIndex);
if (leftSister > GetMin ())
{
parent->LLRotation (parentIndex);
}
94
Função Membro Balance (2)
else if (rightSister > GetMin ())
{
parent->RRRotation (parentIndex);
} // else if (parentIndex + 2 != 0 && ...
else if (leftSister >= rightSister)
{
parent->Concatenation (parentIndex);
}
else
{
parent->Concatenation (parentIndex + 1);
}
}
95
Função Membro PrintTree (1)
void BTree::PrintTree (Visitor visitor, int spaces)
{
if (!IsEmpty ())
{
for (int i = numberOfKeys + 1; i >= 0; --i)
{
if (i <= numberOfKeys)
{
((BTree*) subtree [i])->printTree
(visitor, spaces + 3);
}
96
Função Membro printTree (2)
if (i >= 1 && i <= numberOfKeys)
{
for (int o = spaces; o > 0; --o)
printf (" ");
visitor.Visit (*key [i]);
}
}
}
else if (parent == 0)
throw new ContainerEmptyException
("Arvore vazia!");
}
97
Função Membro GetCountLeftSister
unsigned int BTree::GetCountLeftSister
(unsigned int index)
{
if (index == 0)
return GetMin () - 1;
else
return
parent->subtree [index - 1]-> GetCount();
}
98
Função Membro GetCountRightSister
unsigned int BTree::GetCountRightSister
(unsigned int index)
{
if (index ==
this->parent->numberOfKeys)
return GetMin () - 1;
else
return
parent->subtree [index + 1]-> GetCount();
}
99
Função
Membro
LLRotation
void BTree::LLRotation (unsigned int index)
{
if (isEmpty ())
throw new InvalidOperationException
("Operação inválida!");
int lastPosition;
lastPosition = subtree [index - 1]->GetCount ();
Object & tempKey = subtree[index - 1]->Key(lastPosition);
BTree & tempSubtree =
(BTree&) subtree[index - 1]>Subtree(lastPosition);
((BTree*)subtree [index])->InsertPair(*key [index],
tempSubtree);
key [index] = &tempKey;
((BTree*) subtree [index - 1])->RemovePair (lastPosition);
}
100
Função Membro RRRotation
void BTree::RRRotation (unsigned int index)
{
if (IsEmpty ())
throw new InvalidOperationException
("Operação inválida!");
BTree & tempSubtree =
(BTree &) subtree [index + 1]->Subtree(0);
((BTree*) subtree [index])->InsertPair
(*key [index + 1], tempSubtree);
key[index + 1] = &subtree[index + 1]->Key(1);
((Tree&)subtree [index + 1]->Subtree(0)) =
((Tree&)subtree [index + 1]->Subtree(1));
((BTree*) subtree [index + 1])->RemovePair (1);
}
101
Função Membro Concatenation
void BTree::Concatenation (int index)
{
((BTree*) subtree [index - 1])->InsertPair (*key [index],
(BTree&) subtree [index]->Subtree(0));
for (int i = 1; i <= subtree [index]->GetCount (); ++i)
{
((BTree*) subtree [index - 1])->InsertPair
(subtree [index]->Key(i), (BTree&) subtree [index]->Subtree(i));
}
--numberOfKeys;
for (i = index; i <= numberOfKeys; ++i)
{
key [i] = key [i + 1];
subtree [i] = subtree [i + 1];
}
key [i] = 0;
subtree [i] = 0;
}
102
Função Membro TrimmRoot
void BTree::TrimmRoot ()
{
{
numberOfKeys = subtree [0]->GetCount ();
int i;
for (i = numberOfKeys; i > 0; --i)
{
key [i] = &subtree [0]->Key(i);
subtree [i] = &subtree [0]->Subtree(i);
((BTree*) subtree [i])->parent = this;
}
subtree [i] = &subtree [0]->Subtree(i);
((BTree*) subtree [i])->parent = this;
}
}
103
Função Membro RemovePair
void BTree::RemovePair (unsigned int index)
{
int i;
--numberOfKeys;
for (i = index; i <= numberOfKeys; ++i)
{
key [i] = key [i + 1];
subtree [i] = subtree [i + 1];
}
key [i] = 0;
subtree [i] = 0;
}
104
Função Membro AttachLeftHalfOf
void BTree::AttachLeftHalfOf (BTree const& tree)
{
AttachSubtree (0, *tree.subtree [0]);
numberOfKeys = 0;
for (int ind = 1; ind < tree.m / 2; ++ind)
{
InsertPair (*tree.key [ind],
(BTree&)(*tree.subtree [ind]));
}
}
105
Função Membro AttachRightHalfOf
void BTree::AttachRightHalfOf
(BTree const&, Object& extraKey, BTree& tree)
{
AttachSubtree (0, *tree.subtree [(m + 1) / 2]);
numberOfKeys = 0;
for (int ind = tree.m - 1; ind > tree.m + 1) / 2;
--ind)
{
InsertPair (*tree.key[ind],
(BTree&) *tree.subtree[ind]);
}
}
106
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&);
bool IsFull();
public:
BTree (unsigned int);
BTree (unsigned int, BTree&);
void Insert (Object&);
void Withdraw (Object&);
};
107
Download

Árvores B - Framework de Bruno Preiss