Você está na página 1de 1

public class AVLTree

{
private static class AVLNode // classe privada de nós da árvore
{
public AVLNode left; // atributo para a subárvore esquerda
public AVLNode right; // atributo para a subárvore direita
public int elem; // atributo para o elemento a armazenar na árvore
public int height; // atributo para a altura do nó da árvore

public AVLNode (int pVal) // construtor do nó da árvore


{ elem = pVal; left = right = null; height = 1; }
}

private AVLNode root; // atributo raiz da árvore

public AVLTree () // construtor da árvore


{ root = null; }

public boolean isEmpty () // método de árvore vazia


{ return root == null; }

// métodos públicos e privados da árvore

public int height () // método público da altura da árvore


{ return height (root); }

private static int height (AVLNode pNode) // método privado da altura do nó


{
if (pNode == null) return 0; // teste de árvore vazia – altura 0
else return pNode.height;
}

private static AVLNode singleRightRotation (AVLNode pNode)


{
AVLNode node = pNode.left;
pNode.left = node.right;
node.right = pNode;

// actualizar a altura dos nós envolvidos na rotação


int left = height (pNode.left), right = height (pNode.right);
pNode.height = Math.max (left, right) + 1;
left = height (node.left); right = height (pNode);
node.height = Math.max (left, right) + 1;

return node;
}

private static AVLNode singleLeftRotation (AVLNode pNode)


{
AVLNode node = pNode.right;
pNode.right = node.left;
node.left = pNode;

// actualizar a altura dos nós envolvidos na rotação


int left = height (pNode.left), right = height (pNode.right);
pNode.height = Math.max (left, right) + 1;
left = height (pNode); right = height (node.right);
node.height = Math.max (left, right) + 1;

return node;
}

private static AVLNode doubleRightLeftRotation (AVLNode pNode)


{
pNode.right = singleRightRotation (pNode.right);
return singleLeftRotation (pNode);
}

private static AVLNode doubleLeftRightRotation (AVLNode pNode)


{
pNode.left = singleLeftRotation (pNode.left);
return singleRightRotation (pNode);
}

private static AVLNode balance (AVLNode pRoot)


{
if (pRoot == null) return null; // subárvore vazia

// cálculo da altura das subárvores esquerda e direita


int left = height (pRoot.left), right = height (pRoot.right);

if (left - right == 2) // subárvore esquerda desequilibrada?


{
left = height (pRoot.left.left);
right = height (pRoot.left.right);
if (left >= right) return singleRightRotation (pRoot);
else return doubleLeftRightRotation (pRoot);
}
else if (right - left == 2) // subárvore direita desequilibrada?
{
right = height (pRoot.right.right);
left = height (pRoot.right.left);
if (right >= left) return singleLeftRotation (pRoot);
else return doubleRightLeftRotation (pRoot);
}
else pRoot.height = Math.max (left, right) + 1; // actualizar a altura do nó

return pRoot;
}

public void insert (int pElem) // versão recursiva


{ root = recInsert (root, pElem); }

private static AVLNode recInsert (AVLNode pRoot, int pElem)


{
// árvore vazia - nó colocado na raiz desta árvore
if (pRoot == null) return new AVLNode (pElem);
else if (pRoot.elem > pElem) // subárvore esquerda
pRoot.left = recInsert (pRoot.left, pElem);
else if (pRoot.elem < pElem) // subárvore direita
pRoot.right = recInsert (pRoot.right, pElem);
else return pRoot; // o elemento já existe

return balance (pRoot); // reequilibrar a árvore


}

public void insertRep (int pElem) // versão repetitiva


{
// árvore vazia - nó colocado na raiz desta árvore
if (root == null) { root = new AVLNode (pElem); return; }

Stack<AVLNode> stack = new Stack<AVLNode> (); // criar a pilha


AVLNode node = root, prev = null;
while (node != null)
{
// travessia descendente até encontrar o local de inserção
stack.push (node); // colocar o nó na pilha
prev = node;
if (node.elem > pElem) node = node.left;
else if (node.elem < pElem) node = node.right;
else return; // repetido não é inserido
}

// inserir folha à esquerda ou à direita


if (prev.elem > pElem) prev.left = new AVLNode (pElem);
else prev.right = new AVLNode (pElem);

while (!stack.isEmpty ()) // fazer a travessia ascendente para equilibrar a árvore


{
node = stack.pop (); // retirar o nó da pilha
if (!stack.isEmpty ())
{
prev = stack.pop (); // retirar o nó pai da pilha
// equilibrar o nó actualizando a respectiva subárvore do pai
if (prev.right == node) prev.right = node = balance (node);
else prev.left = node = balance (node);
stack.push (prev); // colocar de novo o nó pai na pilha
}
else root = balance (node); // equilibrar a raiz
}
}

public void delete (int pElem) // versão recursiva


{ if (root != null) root = recDelete (root, pElem); }

private static AVLNode recDelete (AVLNode pRoot, int pElem)


{
if (pRoot == null) return null; // o elemento não existe

if (pRoot.elem > pElem)


pRoot.left = recDelete (pRoot.left, pElem);
else if (pRoot.elem < pElem)
pRoot.right = recDelete (pRoot.right, pElem);
else pRoot = deleteNode (pRoot); // eliminar o elemento

return balance (pRoot); // reequilibrar a árvore


}

private static AVLNode deleteNode (AVLNode pRoot)


{
// nó folha - eliminar o elemento
if (pRoot.left == null && pRoot.right == null) return null;
else if (pRoot.left == null) // com subárvore direita
return pRoot.right; // ligar à direita
else if (pRoot.right == null) // com subárvore esquerda
return pRoot.left; // ligar à esquerda
else // com subárvores esquerda e direita
{
// substituir pelo menor elemento da subárvore direita
pRoot.elem = findMin (pRoot.right);
// remover o menor elemento da subárvore direita
pRoot.right = recDelete (pRoot.right, pRoot.elem);
return pRoot;
}
}

private static int findMin (AVLNode pRoot)


{
AVLNode node = pRoot;
while (node.left != null) node = node.left;
return node.elem;
}

public void deleteRep (int pElem) // versão repetitiva


{
if (root == null) return; // árvore vazia

Stack<AVLNode> stack = new Stack<AVLNode> (); // criar a pilha

AVLNode delnode = root, prev = null;


while (delnode != null && delnode.elem != pElem)
{
// travessia descendente até encontrar o elemento a remover
stack.push (delnode); // colocar o nó na pilha
prev = delnode;
if (delnode.elem > pElem) delnode = delnode.left;
else delnode = delnode.right;
}

if (delnode == null) return; // elemento inexistente na árvore

AVLNode node = delnode; // elemento a remover

if (node.right == null) node = node.left; // ligar à esquerda


else if (node.left == null) node = node.right; // ligar à direita
else // com subárvores esquerda e direita
{
// procurar menor elemento da subárvore direita
stack.push (node); // colocar o nó na pilha

AVLNode tmp = node.right, prevtmp = node;


while (tmp.left != null)
{ prevtmp = tmp; stack.push (tmp); tmp = tmp.left; }

node.elem = tmp.elem; // substituir pelo menor elemento


// desligar o menor elemento e ajustar as ligações
if (prevtmp == node) prevtmp.right = tmp.right;
else prevtmp.left = tmp.right;
}

// ajustar o pai do elemento removido que só tem um filho


if (delnode == root) root = node; // caso tenha sido removido da raiz
else if (prev.left == delnode) prev.left = node;
else prev.right = node;

while (!stack.isEmpty ()) // fazer a travessia ascendente para equilibrar a árvore


{
node = stack.pop (); // retirar o nó da pilha
if (!stack.isEmpty ())
{
prev = stack.pop (); // retirar o nó pai da pilha
// equilibrar o nó actualizando a respectiva subárvore do pai
if (prev.right == node) prev.right = node = balance (node);
else prev.left = node = balance (node);
stack.push (prev); // colocar de novo o nó pai na pilha
}
else root = balance (node); // equilibrar a raiz
}
}
}

Você também pode gostar