Arvore de dados

Olá a todos.
Estou fazendo um programa que necessita de uma estrutura de dados em arvore, para que ao inserir uma determinada sequencia, seja de letras ou numeros, e que possa ser mostrar todas as possibilidades possiveis sobre ela.Porém tenho um problema no armazenamento dos dados, quando ele tenta fazer a verificação da informção que se encontra em um campo “proximo” a ele, ele somente consegue ver até a segunda informção, após a terceira ele começa a repetir a informação desde o primeiro, sendo assim, ele sempre repete a primeira e a segunda informação no primeiro nivel.
Serei grato se puderem me ajudar!
O codigo é esse:

import java.util.ArrayList;

/** Classe destinada a armazenar dados em uma estrutura em Arvore. */
public class Arvore
{	private int nivel;
	private Arvore anterior;
	private ArrayList<Arvore> proximos;
	private int posLetra;
	private char letra;
	
	public Arvore()
	{	
	}
	
	public Arvore(int nivel, Arvore anterior, int posLetra, char letra)
	{	this.nivel = nivel;
		this.anterior = anterior;
		this.proximos = new ArrayList<Arvore>();
		this.posLetra = posLetra;
		this.letra = letra;
	}
	
	public int getNivel()
	{	return nivel;
	}
	
	public Arvore getAnterior()
	{	return anterior;
	}
	
	public ArrayList<Arvore> getProximos()
	{	return proximos;
	}
	
	public int getPosLetra()
	{	return posLetra;
	}
	
	public char getLetra()
	{	return letra;
	}
	
	/** Adiciona uma arvore na lista do nodo anterior. */
	public void setProximos(Arvore arvore)
	{	this.proximos.add(arvore);
	}
	
	/** verifica se os niveis anteriores possuem o valor passado. */
	public boolean verificaAnteriores (Arvore superior, int valor)
	{	Arvore parcial = superior;		//Armazena parcialmente a raiz superior que é passada.
		boolean resultado = false;		/*Resultado é instanciado com falso para indicar que o
										* valor passado não é igual aos anteriores*/
		
		while(parcial.getAnterior() != null)
		{	if(valor == parcial.getPosLetra())
			{	resultado = true;		//Indica que o valor já existe.
			}
			//Parcial recebe um nodo superior.
			parcial = parcial.getAnterior();
		}
		
		return resultado;
	}
	
	/** Verificia se na lista de proximos de um nodo contem o valor especificado */
	public boolean verificaListaProx(Arvore superior, int valor)
	{	ArrayList<Arvore> lista  = superior.getProximos();
		Arvore parcial;									//Armazena parcialmente nodo de uma arvore.
		boolean resultado = false;						/*Resultado é instanciado com falso para indicar que o
		 												* valor passado não é igual aos proximos */
		
		//Verifica se, houver proximos, a existencia do valor passado.
		if(!lista.isEmpty())
		{	parcial = lista.remove(0);					//Remove sempre o primeiro item da lista.
			if(parcial.getPosLetra() == valor)
			{	resultado = true;						//Indica que o valor já existe.
			}
		}
		
		return resultado;
	}
	
	/** Adiciona uma arvore na lista do nodo anterior. */
	public Arvore criaRaiz(int nivel, Arvore superior, String palavra)
	{	Arvore resultado;				//Armazena o resultado dessa operação.
		int i,j = 0;					//Variaveis temporarias, para realizar as operações.
		int k = palavra.length() - 1;	//Variavel para armazenar a posição da ultima letra da palavra.
		
		//Estrutura de repetição para verificar se o numero é identico aos anteriores 
		//ou a lista de proximos do nodo superior.
		for(i = 0; i < palavra.length(); i++)
		{	if(verificaAnteriores(superior,i) || verificaListaProx(superior,i))
			{	j++;
			}
			else
			{	//Caso o valor seja o menor até agora, este será armazenado.
				if(j < k)
				{	k = j;
				}
			}
		}
		
		resultado = new Arvore(nivel, superior, k, palavra.charAt(k));
		System.out.println("Criada raiz: " + palavra.charAt(k) + " nivel: " + nivel);
		
		for(i = nivel + 1; i < palavra.length(); i++)
		{	resultado.setProximos(criaRaiz(nivel + 1, resultado, palavra));
		}
		
		return resultado;
	}
	
	/** metodo para criar uma arvore */
	public void criaArvores(String palavra)
	{	int i , j;
		
		for(i = 0; i < palavra.length(); i++)
		{	Arvore raiz = new Arvore(0, new Arvore(), i, palavra.charAt(i));
			System.out.println("Criada arvore: " + palavra.charAt(i));
			
			for(j = 1; j < palavra.length(); j++)
			{	raiz.setProximos(criaRaiz(1,raiz,palavra));
			}
		}
	}
	
}

Fala, Wolf, tudo bem?

Você chegou a bolar algum teste unitário pra sua classe?

[quote=erictorti]Fala, Wolf, tudo bem?

Você chegou a bolar algum teste unitário pra sua classe?[/quote]

Sim, coloquei como entrada ‘ABCD’, e a saida foi esta:

Criada arvore: A
Criada raiz: B nivel: 1
Criada raiz: C nivel: 2
Criada raiz: D nivel: 3
Criada raiz: D nivel: 2
Criada raiz: C nivel: 3
Criada raiz: C nivel: 1
Criada raiz: B nivel: 2
Criada raiz: D nivel: 3
Criada raiz: D nivel: 2
Criada raiz: B nivel: 3
Criada raiz: B nivel: 1
Criada raiz: C nivel: 2
Criada raiz: D nivel: 3
Criada raiz: D nivel: 2
Criada raiz: C nivel: 3

No nivel 1, o B se repete.
Gostaria que ao inves de aparecer um segundo ‘B’ no nivel um aparecesse ‘D’.

Legal, deu pra sacar o comportamento da classe como um todo.

Mas como é uma estrutura razoavelmente complexa, seria legal pensar em testar unitariamente cada método público dela.

Assim você quebraria o problema em partes menores e, de quebra, teria uma especificação pro comportamento da sua classe.

Desculpe, acho que não havia entendido a sua pergunta direito, mas o que eu venho percebendo é que a função verificaListProx esta com algum problema, ela não consegue “ver” corretamente as informações que estão “proximas” a ela.
Algum tipo de erro esta na ArrayList dela, não sei se é porque a cada nivel que a função chama ela vai sobrepondo dados na ArrayList.

A saída esperada seria essa?

Criada arvore: A
Criada raiz: B nivel:
Criada raiz: C nivel: 2
Criada raiz: D nivel: 3
Criada raiz: D nivel: 2
Criada raiz: C nivel: 3
Criada raiz: C nivel: 1
Criada raiz: B nivel: 2
Criada raiz: D nivel: 3
Criada raiz: D nivel: 2
Criada raiz: B nivel: 3
[color=blue]Criada raiz: D nivel: 1
Criada raiz: B nivel: 2
Criada raiz: C nivel: 3
Criada raiz: C nivel: 2
Criada raiz: B nivel: 3[/color]

Exato!
Conseguiu chegar a esse resultado?

Hehe. Ainda não :slight_smile:

Estou pensando em alguma abordagem mais modularizada pro problema. A lógica da classe está um pouco complicada de entender.

Hehehe
Obrigado por estar tentando. :slight_smile:

Fala, wolf, beleza?

Desculpa a demora em responder. Mas é que achei seu problema legal pra fazer uma experiência de TDD baby-steps :]

Fui bolando os testes e a classe foi tomando forma.

Não sei se se aplica ao seu problema, mas consegui um output aparentemente correto para um Node(“ABCD”).apresenteSe(); e a classe ficou razoavelmente enxuta.

Lógico que tem vários pontos a melhorar, mas acho que é um esboço legal pra abordar o problema que você está enfrentando.

Ah. Precisei de uma classezinha utililitária e pra rodiziar uma String tipo ABCD vira BCDA. Fiz outra classe pra ficar melhor de testar.

Seguem os códigos das classes e os respectivos testes.

public class Node {

	public List<Node> filhos = new ArrayList<Node>();
	public int nivel;
	private char nome;
	private String elementos;
	
	public Node(String elementos, int nivel) {
		this.elementos = elementos;
		this.nivel = nivel;
		comeUmEProcria();
	}

	public Node(String elementos) {
		this(elementos, 0);
	}

	private void comeUmEProcria() {
		comeUm();
		procria();
	}
	
	private void comeUm() {
		nome = elementos.charAt(0);
		
		if(elementos.length() > 0) {
			elementos= elementos.substring(1); 
		} else {
			elementos = null;
		}
	}

	private void procria() {
		if (elementos != null) {
			for (int i = 0; i < elementos.length(); i++) {
				Node filho = new Node(elementos, nivel + 1);
				filhos.add(filho);
				elementos = new RodiziadorDeElementos().roda(elementos);
			}
		}
	}
	
	public void apresenteSe() {
		StringBuilder sb = new StringBuilder();
		
		if(this.nivel == 0) 
			sb.append("Criada árvore: ");
		else 
			sb.append("Criada raiz: ");
		
		sb.append(this.getNome());
		
		if(this.nivel != 0 ) {
			sb.append(" de nível: ");
			sb.append(this.getNivel());
		}
		
		sb.append("\n");
		
		System.out.println(sb);
		
		for (Node filho : getFilhos()) {
			filho.apresenteSe();
		}
	}

	
	
	public List<Node> getFilhos() {	return filhos; }

	public int getNivel() { return nivel; }

	public char getNome() { return nome; }
	
}
public class TestaNode {

	@Test
	public void nodeDeUmElementoNaoPossuiFilhos() throws Exception {
		Node A = new Node("A");
		List<Node> filhos = A.getFilhos();
		Assert.assertEquals(0, filhos.size());
	}
	
	@Test
	public void nodeSabeSeuNivel() throws Exception {
		Node A = new Node("A");
		Assert.assertEquals(0, A.getNivel());
	}

	@Test
	public void nodeSabeSeuNome() throws Exception {
		Node A = new Node("A");
		Assert.assertEquals('A', A.getNome());
	}
	
	@Test
	public void nodeDeDoisElementosPossuiUmFilho() throws Exception {
		Node AB = new Node("AB");
		List<Node> filhos = AB.getFilhos();
		Assert.assertEquals(1, filhos.size());
	}
	
	@Test
	public void nodeDeDoisElementosPossuiUmFilhoDeNivel1() throws Exception {
		Node AB = new Node("AB");
		List<Node> filhos = AB.getFilhos();
		Node B = filhos.get(0);
		Assert.assertEquals(1, B.getNivel());
	}
	
	@Test
	public void nodeDeDoisElementosBPossuiUmFilhoChamadoB() throws Exception {
		Node AB = new Node("AB");
		List<Node> filhos = AB.getFilhos();
		Node B = filhos.get(0);
		Assert.assertEquals('B', B.getNome());
	}
	
	@Test
	public void nodeDeTresElementosPossuiDoisFilhosDeNivel() throws Exception {
		Node ABC = new Node("ABC");
		List<Node> filhos = ABC.getFilhos();
		Assert.assertEquals(2, filhos.size());
	}
	
	@Test
	public void nodeDeTresElementosPossuiUmFilhoChamadoBDeNivel1() throws Exception {
		Node ABC = new Node("ABC");
		List<Node> filhos = ABC.getFilhos();
		Assert.assertEquals('B', filhos.get(0).getNome());
		Assert.assertEquals(1, filhos.get(0).getNivel());
	}
	
	@Test
	public void nodeDeTresElementosPossuiUmFilhoChamadoCDeNivel1() throws Exception {
		Node ABC = new Node("ABC");
		List<Node> filhos = ABC.getFilhos();
		Assert.assertEquals('C', filhos.get(1).getNome());
		Assert.assertEquals(1, filhos.get(1).getNivel());
	}
	
	@Test
	public void nodeDeTresElementosPossuiBDeNivel1QuePossuiFilhoDDeNivel2() throws Exception {
		Node ABC = new Node("ABC");
		List<Node> filhos = ABC.getFilhos();
		Node filhoB = filhos.get(0);
		Node netoC = filhoB.getFilhos().get(0);
		Assert.assertEquals('C', netoC.getNome());
		Assert.assertEquals(2, netoC.getNivel());
	}
	
	@Test
	public void nodeABCDseApresentaCorretamente() throws Exception {
		Node ABCD = new Node("ABCD");
		ABCD.apresenteSe();
	}
	
}
public class RodiziadorDeElementos {

	public String roda(String elementos) {
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < elementos.length(); i++) {
			int proximaPosicao = i + 1;
			
			if(proximaPosicao < elementos.length())
				sb.append(elementos.charAt(proximaPosicao));
			else
				sb.append(elementos.charAt(0));
		}
		return sb.toString();
	}
}

[code]
public class TestaRodiziadorDeElementos {

@Test
public void casoRecebaARodaDevolveA() throws Exception {
	String A = new RodiziadorDeElementos().roda("A");
	assertEquals("A", A);
}

@Test
public void casoRecebaABDevolveBA() throws Exception {
	String BA = new RodiziadorDeElementos().roda("AB");
	assertEquals("BA", BA);
}

@Test
public void casoRecebaABCDevolveBCA() throws Exception {
	String BCA = new RodiziadorDeElementos().roda("ABC");
	assertEquals("BCA", BCA);
}

@Test
public void casoRecebaABCDDevolveBCDA() throws Exception {
	String BCDA = new RodiziadorDeElementos().roda("ABCD");
	assertEquals("BCDA", BCDA);
}

}[/code]

Qualquer erro, por favor, me avise :]

Abração.

Eric

Nossa Eric, ficou legal.
Mas infelizmente o que eu queria era um codigo que fosse dinamico, que eu pudesse fornecer qualquer entrada, podendo ter infinitos elementos, não somente limitado ao ‘ABCD’, podendo ser numeros ou palavras.
Não sei se estou sendo claro, então fiz esses diagramas:

Um exemplo com 3 elementos.

Um exemplo com 4 elementos.

Onde os numeros em azul indicam os elementos de entrada, os pretos seriam a propria arvore, e posteriormente eu criaria uma função de leitura que poderia percorer todos esses nós e me retornar os valores em verde.

Nos testes que eu faço, eu vejo que o erro se encontra no verificaListaProx, que não retornar corretamente os nós ‘Proximos’ de um nivel superior, agora não sei se o erro esta na logica ou na ArrayList, eu até já tentei usar Queue, mas este parece que não funiona muito bem…

Sou muito grato por ter tentado me ajudar, e gostei do seu algoritmo. :smiley:

Legal, saquei o problema.

Esse algoritmo que montei é bacana, mas ele tá há uns 20min rodando Node(“ABCDEFGHQOEOUHKLALAOIUQLKJHGOIUYQALKJHOIUYGLK”).apresenteSe(); por causa da recursão :slight_smile:

Vou conversar com o pessoal daqui e ver se alguém tem uma sugestão.

Valeu.

Abraço.

Não tem a estrutura da árvore mas imprime o que queres. Tens a base para o algoritmo, agora adapta para o que precisas.

public class Arvore {

    public static void main(String args[]) {
        String seq = "1234";
        Arvore arvore = new Arvore();
        arvore.proccess(seq.toCharArray());

    }

    private void proccess(char[] sequencia) {
        for (int i = 0; i < sequencia.length; i++) {
            add(new char[] {}, sequencia[i], removeChar(sequencia, i));
        }
    }

  private void add(char[] seq, char c, char[] remain) {
        char newSeq[] = new char[seq.length + 1];
        for (int i = 0; i < seq.length; i++) {
            newSeq[i] = seq[i];
        }
        newSeq[seq.length] = c;

        if (remain.length == 0) {
            for (int i = 0; i < newSeq.length; i++) {
                System.out.print(newSeq[i]);
            }
            System.out.println();
        } else {
            for (int i = 0; i < remain.length; i++) {
                add(newSeq, remain[i], removeChar(remain, i));
            }
        }

    }

    private char[] removeChar(char[] c, int pos) {
        char[] result = new char[c.length - 1];
        for (int i = 0; i < pos; i++) {
            result[i] = c[i];
        }
        for (int i = pos + 1; i < c.length; i++) {
            result[i - 1] = c[i];
        }
        return result;
    }

}

:-o
Nossa muito bom esse algoritmo, acho que vai me servir bem, apesar de não ser a estrutura que eu queria.

Agradeço a todos que me ajudaram!
:smiley: