1.08k likes | 1.22k Views
Árvores B. Implementação pelos FrameWork Bruno Preiss. Árvores B. FrameWork Java de Bruno Preiss. Framework de Árvores e Busca. Interface Comparable. //pgm05_01.txt public interface Comparable { boolean isLT (Comparable object); boolean isLE (Comparable object);
E N D
Árvores B Implementação pelos FrameWork Bruno Preiss
Árvores B FrameWork Java de Bruno Preiss
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); }
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; }
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 ()); } // ... }
Interface Container public interface Container extends Comparable { int getCount (); boolean isEmpty (); boolean isFull (); void purge (); void accept (Visitor visitor); Enumeration getEnumeration (); }
Interface SearchableContainer public interface SearchableContainer extends Container { boolean isMember (Comparable object); void insert (Comparable object); void withdraw (Comparable obj); Comparable find (Comparable object); }
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); }
Interface SearchTree //pgm10_01.txt public interface SearchTree extends Tree, SearchableContainer { Comparable findMin (); Comparable findMax (); }
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; } // ... }
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 ()); } } // ... }
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; } // ... }
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
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); } }
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ó
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; }
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; } // ... }
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)
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); } }
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
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
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)
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; }
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); } } }
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
Método attachSubtree public void attachSubtree (int i, MWayTree arg) { BTree btree = (BTree) arg; subtree [i] = btree; btree.parent = this; }
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]); } }
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]); } }
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
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); } }
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; }
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
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; } }
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; }
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
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
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
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); }
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 (); }
Métodos getMin e isFull public int getMin () { return ((getM () + 1) / 2) - 1; } public boolean isFull () { return getM () - 1 == count; }
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
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); } }
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!"); }
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()
Método getCountLeftSister public int getCountLeftSister (int index) { if (index == 0) return getMin () - 1; else return parent.subtree [index - 1].getCount (); }
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()
Método getCountRightSister public int getCountRightSister (int index) { if (index == this.parent.count) return getMin () - 1; else return parent.subtree [index + 1].getCount (); }
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