Inserção_Remocao_ArvoreAVL

Gente essa implementação é de uma inserção e remoção em uma árvore AVL.
Não consigo descobrir o que tem de errado que não está rotacionando a árvore corretamente quando insiro os elementos: 8, 5, 10, 3, 4. Ele tira o 10 da exibição e repete o 5 duas vezes. Além disso, coloca a subárvore do 4 no lado errado.
Já olhei uma porção de vezes e não consigo achar. :frowning:
Segue o código abaixo:

package Ins_Rem_Arvore;

import Ins_Rem_Arvore.Node;

public class Node 
{
	public int info;//atributo que guarda a informação do no
	public Node dir;//atributo que aponta para o no esquerdo
	public Node esq;//atributo que aponta para o no direito
	public Node pai;//atributo que aponta para o pai do no
	public int balanco; //atributo utilizado apenas na arvore avl. balanco = altura(arvore a esq) - altura(arvore a dir)
	
	//construtor com entrada da chave
	public Node(int x)
	{
		this.info = x;
		this.dir = null;
		this.esq = null;
		this.pai = null;
		this.balanco = 0;
	}
	/*========================================================================================*/
	//construtor padrao
	public Node()
	{
		
	}
	/*========================================================================================*/
	//construtor com entrada da chave e Node dir e esq
	public Node(int x,Node esq,Node dir)
	{
		this.info = x;
		this.dir = dir;
		this.esq = esq;
		this.pai = null;
		this.dir.pai = this;
		this.esq.pai =this;

	}
}

[code]
package Ins_Rem_Arvore;

import javax.swing.JOptionPane;

import Ins_Rem_Arvore.Node;

/** Arvore AVL
*/
public class ArvoreAvl
{
private boolean t; //controlador do balanceamento da arvore
private int local; //localiza se o pai do no removido vai ter um novo
private Node raiz; // no raiz da arvore
private Node pt; // no de percurso
private Node aux;// no auxiliar de percurso (guarda o ultimo no acessado)
private int pos; // posicao do no, 1 = esquerda, 2 = direita
private String print; //atributo para impressao da arvore

/*========================================================================================*/
public ArvoreAvl()
{
	this.raiz = null;
	this.pt = null;
	this.aux = null;
	this.print = " ";
}

/*========================================================================================*/
//Metodo que executa a rotacao direita 
private void rotacaoDireita(Node p,boolean h)
{
	Node ptu = new Node();
	boolean testeraiz = false; //testa se o no e a raiz
		
	if (p == raiz) 
		testeraiz = true;
			
	ptu = p.esq;
	if (ptu.balanco == -1)
	{ 	  
		p.esq = ptu.dir;  //seu filho a esquerda sera o filho a direita de seu filho
		if (ptu.dir != null)
		{ 
			ptu.dir.pai = p;  //novo pai
		}
				
		if (p !=raiz)
		{ 
			p.pai.esq = ptu; 
		}	  
		
		ptu.pai = p.pai;
		ptu.dir = p;
		p.pai = ptu;
		p.balanco = 0;
		p = ptu;
		if (testeraiz) 
			raiz = ptu; 
	}
	else
	{ //rotacao dupla direita
		Node ptv = new Node();
		ptv = ptu.dir;
		ptu.dir = ptv.esq;
		
		if (ptv.esq != null)
		{
			ptv.esq.pai= ptu;
		}
			
		ptv.esq = ptu;
		ptu.pai = ptv;
		p.esq = ptv.dir;
			
		if (ptv.dir !=null)
		{
			ptv.dir.pai = p;
		}
				
		ptv.dir = p;
		
		if (p.pai !=null)
		{
			p.pai.dir = ptv;
		} //o pai de p tera ptv como seu novo filho a direita
				
		ptv.pai = p.pai;
		p.pai =ptv;
			
		if (ptv.balanco == -1)
			p.balanco = 1;
		else 
			p.balanco = 0;
				
		if (ptv.balanco == 1) 
			ptu.balanco = -1;
		else 
			ptu.balanco = 0;
				
		if (testeraiz)
			raiz = ptv; 
			
		p = ptv;
	}
			
	p.balanco = 0;
	t = false;
			
	}
/*========================================================================================*/
//Metodo que executa a rotacao esquerda 
private void rotacaoEsquerda(Node p,boolean h)
{
	Node ptu = new Node();
	boolean testeraiz = false;
		
	if (p == raiz) 
		testeraiz = true;
		
	ptu = p.dir;
	if (ptu.balanco == 1)
	{ 	  
		p.dir = ptu.esq;  //seu filho a direita sera o filho a esquerda de seu filho
				
		if (ptu.esq != null)
		{ 
			ptu.esq.pai = p;  //novo pai
		}
				
		if (p !=raiz) 
		{
			p.pai.dir = ptu;
		}  //o pai de p tera o filho a direita de p como seu novo filho a direita
				
		ptu.pai = p.pai;
		ptu.esq = p;
		p.pai = ptu;
		p.balanco = 0;
		p = ptu;
				
		if (testeraiz) 
			raiz = ptu; 
	}
	else
	{ 
		//rotacao dupla esquerda
		Node ptv = new Node();
		ptv = ptu.esq;
		ptu.esq = ptv.dir;
				
		if (ptv.dir !=null)
		{	
			ptv.dir.pai= ptu;
		}
		ptv.dir = ptu;
		ptu.pai = ptv;
		p.dir = ptv.esq;
				
		if (ptv.esq !=null)
		{
			ptv.esq.pai = p;
		}
				
		ptv.esq = p;
				
		if (p.pai !=null)
		{
			p.pai.esq = ptv;
		} 
				
		p.pai =ptv;
			
		if (ptv.balanco == 1)
			p.balanco = -1;
		else 
			p.balanco = 0;
				
		if (ptv.balanco == -1) 
			ptu.balanco = 1;
		else 
			ptu.balanco = 0;
				
		if (testeraiz)
			raiz = ptv;
	
		p = ptv;
	}
	p.balanco = 0;
	t = false;
}
		
/*========================================================================================*/
//Metodo de insercao de um elemento na arvore
public boolean inserirElemento(int x)
{
	pt = new Node(x);
	if (raiz == null)
	{			
		raiz = pt;
	}//se arvore vazia, insere na raiz
	else
	{
		pt = raiz; 
		insAVL(x,pt,false);
	}
	return true;
}

/*========================================================================================*/	
//Metodo que auxilia o metodo inserirElemento() para insercao e balanceamnto
private boolean insAVL(int x,Node pt,boolean h)
{
	t = h; 
	if (pt == null)
	{//No alocado no espaco vazio
		pt = new Node(x);
		if(pos==1)
		{
			aux.esq= pt;
		} 
		else if (pos == 2)
		{
			aux.dir = pt;
		}
			
		pt.pai = aux;//pai do no
		t=true;
		pos=0;
	}
	else
	{
		if (x == pt.info)
		{ //ja existe element na arvore
			pt = null;
			return false;
		}
		if (x < pt.info)
		{//chave menor que o no
			aux = pt;	 //aux sera o pai do no inserido
			pos = 1;	 // filho a esquerda de aux
			insAVL(x,pt.esq,t);
			//depois da insercao, a verificacao
			if (t)
			{
				if (pt.balanco == 1)
				{
					pt.balanco = 0;
					t = false;
				}
				else if (pt.balanco == 0) 
					pt.balanco = -1;
				else if (pt.balanco == -1) 
					rotacaoDireita(pt,t); //rebalanceamento (rotacao direita)
			}
		}
		else
		{//chave maior que o no
				aux = pt; //aux sera o pai do no inserido
				pos = 2;  // filho a direita de aux
				insAVL(x,pt.dir,t);
			
				//depois da insercao, a verificacao
			if (t)
			{
				if (pt.balanco == -1)
				{
					pt.balanco = 0;
					t = false;
				}
				else if (pt.balanco == 0) 
					pt.balanco = 1;
				else if (pt.balanco == 1) 
					rotacaoEsquerda(pt,t); //rebalanceamento (rotacao esquerda)
			}
		}
	}
	return true;
}
		
/*========================================================================================*/	
//Metodo de remocao de um elemento na arvore
public boolean removerElemento(int x)
{
	if (raiz == null)
	{
		return false;
	}//arvore vazia
	else
	{
		pt = raiz;//no de percurso
		remAVL(x,pt,false);
	}
	return true;
}

/*========================================================================================*/	
//Metodo auxiliar para remocao do no x e balanceamento da arvore
public boolean remAVL(int x,Node pt,boolean h)
{
	t=h;

	if (pt == null)
	{
		return false;
	}//nao achou
	else
	{
		if (x == pt.info )
		{
			//*******REMOCAO*******/
			if (pt.esq == null && pt.dir == null)
			{
				//no sem filhos
				if (pt == raiz) 
				{
					raiz = null;
				}
				else
				{
					if (pos == 1)//este no e' o filho da esquerda do seu pai
						pt.pai.esq = null;
					else if(pos == 2)//este no e' o filho da direita do seu pai
						pt.pai.dir = null;
				}
				
				pt =null;
				t = true;
			}
			else 
			{
			//tem filhos
				aux = pt;
				if (pt.esq == null)
				{ //pode ter apenas o filho da direita
					pt = pt.dir;
					local = 1; //pai de pt tera novo filho a direita
				}
				else
				{
					if (pt.dir == null)
					{//tem apenas o filho da esquerda
						pt = pt.esq;
						local = 2; //pai de pt tera novo filho a esquerda
					}
					else
					{//tem dois filhos
						pt = minDir(aux.dir);	//achar o menor a direita
						pt.esq = aux.esq;	//reordenacao de ponteiros
						if (aux == raiz)
						{
							raiz = pt;
						}//se o no a ser removido era a raiz, pt e' a nova raiz
						else 
						{ 
							pt.pai = aux.pai;
							if (pos == 1)//este no e' o filho da esquerda do seu pai
								aux.pai.esq =pt;
							else if(pos == 2)//este no e' o filho da direita do seu pai
								aux.pai.dir =pt;
						}
						aux = null;
						return true;
					}	
				}
			}
			if (aux == raiz)
			{
				raiz = pt;
			}//se o no a ser removido era a raiz, pt e' a nova raiz
			else
			{//nao e a raiz(tem pai)
				if (local == 1)
				{
					aux.pai.dir = pt;
				} //pai tem filho a direita
				else if (local == 2) 
				{
					aux.pai.esq = pt; 
				}//pai tem filho a esquerda
			}
			aux = null;
		}
		//Continua a pesquisa
		else
		{
			if (x < pt.info)
			{//procura na esquerda
				aux = pt;
				pos=1;
				remAVL(x,pt.esq,t);
				//depois da remocao, a verificacao
				if (t)
				{
					if(pt.balanco == -1)
						pt.balanco = 0;
				
					t = false;
				}
				else if (pt.balanco == 0) 
					pt.balanco = 1;
				else if (pt.balanco == 1)
					rotacaoEsquerda(pt,t);//rebalanceamento (rotacao esquerda)
			}
			else
			{ //procura na direita
				aux = pt;
				pos=2;
				remAVL(x,pt.dir,t);
				//depois da remocao, a verificacao
				if (t)
				{
					if (pt.balanco == 1)
					{
						pt.balanco = 0;
						t = false;
					}
					else if (pt.balanco == 0) 
						pt.balanco = -1;
					else if (pt.balanco == -1) 
						rotacaoDireita(pt,t); //rebalanceamento (rotacao direita)
				}
			}
		}
	}
	
	local=0; //sem valor, ao final da execucao
	return true;
	}

/*========================================================================================*/
/*Metodo auxiliar para o metodo da remocao. Acha o no de menor chave ao lado direito do no dado */
protected Node minDir(Node p)
{
	if (p.esq ==null) 
		return p;
	else
	{ 
		p = p.esq;
		return minDir(p);
	}
}	
/*========================================================================================*/
/*Metodo que exibe a arvore na representacao de parenteses aninhados*/
public String exibirArvorePreOrdem()
{
	if (raiz == null)
		return ""; 
	
	Node p = this.raiz; // recebe o no raiz
	print = print + Integer.toString(p.info)+ " ";
	if (p.esq != null)
	{
		print = print + "(" + exibirArvorePreOrdem(p.esq)+")";
	}
	if (p.dir != null)
	{
		print = print + "(" + exibirArvorePreOrdem(p.dir)+ ")";
	}
	String pr = print;
	print = " ";
	return pr;
}

/*========================================================================================*/
//Metodo que exibe a arvore em pre ordem 
private String exibirArvorePreOrdem(Node p)
{
	print = Integer.toString(p.info)+ " ";
	if (p.esq != null)
	{
		print = print + "( " + exibirArvorePreOrdem(p.esq) + " ) ";
	}
	if (p.dir != null)
	{
		print = print + " ( " + exibirArvorePreOrdem(p.dir)+ " ) ";
	}
	String pr = print;
	print = " ";
	return pr;
}

/*========================================================================================*/
//Metodo de execucao da Arvore AVL
public void interfaceUsuario()
{	
	String parametro;
	String tipodeOperacao = " ";
	boolean testeOperador=false;
	boolean testeParametro=false;
		
	while (tipodeOperacao != null)
	{
		tipodeOperacao = JOptionPane.showInputDialog(" Entre com o tipo de operacao que deseja fazer:\n" +
													 " [1] Insercao \n [2] Remocao\n ");
				
		if(tipodeOperacao == null || tipodeOperacao.length() == 0)
		{
			return;
		}//entrada vazia(cancelamento do panel)
	
		for(int j =0; j < tipodeOperacao.length(); j++)
		{//testa se entrada nao é inteiro
			if (!Character.isDigit(tipodeOperacao.charAt(j)))
			{ 
				testeOperador =true;
			}	
		} 
		
		if (testeOperador)
		{
			JOptionPane.showMessageDialog( null,"Entrada incorreta (entre com um numero de 1 a 2)", " Arvore AVL ",
										   JOptionPane.PLAIN_MESSAGE );
		}
		else
		{
			 if( ( tipodeOperacao.equals("1") ) || ( tipodeOperacao.equals("2") ) )
			 {
					parametro = JOptionPane.showInputDialog("Entre com o parametro da operacao (Int)");
			
					if (parametro == null ||parametro.length() == 0)
					{
						return;
					}//teste de cancelamento ou entrada vazia

					for(int j =0; j < parametro.length(); j++)
					{
						if (!Character.isDigit(parametro.charAt(j)))
						{ //testa se entrada nao é inteiro
							testeParametro = true;
						}	
					}
					
					if(testeParametro)
					{
						JOptionPane.showMessageDialog(null,"Entrada incorreta (somente inteiros)"," Arvore B ",JOptionPane.ERROR_MESSAGE);
					}
					else
					{
						int x = Integer.parseInt(parametro);
						
						//INSERCAO
						if(tipodeOperacao.length() == 1 && tipodeOperacao.charAt(0) == '1')
						{
							this.inserirElemento(x);
							JOptionPane.showMessageDialog(null,"A arvore atual e': " + exibirArvorePreOrdem()
									                      ,"Impressao",JOptionPane.PLAIN_MESSAGE);
						}
						//REMOCAO
						else if(tipodeOperacao.length() == 1 && tipodeOperacao.charAt(0) == '2')
						{
							this.removerElemento(x);
							JOptionPane.showMessageDialog(null,"A arvore atual e': " + exibirArvorePreOrdem()
									                      ,"Impressao",JOptionPane.PLAIN_MESSAGE);
						}
						else if(tipodeOperacao == null)
						{//cancelou 
							return; //teste de cancelamento
						}
						else
						{//Se diferente de todas as outras opcoes, entrada incorreta
							JOptionPane.showMessageDialog(null,"Entrada incorreta"," Arvore AVL ",
									                      JOptionPane.ERROR_MESSAGE);
						}
					}
			 }
			 else
			 {
				 JOptionPane.showMessageDialog( null,"Entrada incorreta (entre com um numero de 1 a 2)",
                                                " Arvore AVL ",JOptionPane.PLAIN_MESSAGE );							
			 }
		}	
	}
}

}[/code]

package Ins_Rem_Arvore;

import Ins_Rem_Arvore.ArvoreAvl;

public class ChamaArvoreAVL 
{
	public static void main(String[] args) 
	{
		ArvoreAvl inicio = new ArvoreAvl();
		inicio.interfaceUsuario();
	}
}