Ho un problema, grande con un esercizio sugli alberi, è questo:

codice:
Si realizzi un'implementazione dell'interfacce Tree<E>, mostrata nella pagine seguente,
che rappresenti un albero radicato generico. Si realizzi anche una classe Java denominata
Triple, che rappresenti una tripla di valori interi compresi tra 1 e 9 (estremi inclusi).
In seguito si realizzi un programma Java che preso in input un file contenente una lista di
triple costruisca un albero completo (Tree<Triple>) dove ogni nodo possiede un numero
costante di figli. Gli elementi verranno forniti in ordine nella lista in modo da costruire
l'albero inserendo i valori nei nodi procedendo attraverso una visita postorder dell'albero.
Il programma dovrà stampare in un file di output la visita preorder dell'albero ottenuto,
utilizzando il metodo toString() fornito dalla classe Tree.
Input
Il file di input contiene una lista di terne di valori interi, una per riga, racchiuse tra
parentesi. La prima riga del file contiene due valori interi, separati da una virgola, che
specificano l'altezza dell'albero e il numero di figli di ciascun nodo.
Output
Il file di output dovrà contenere una lista di triple, una per riga, racchiuse tra parentesi e
risultanti dalla visita preorder dell'albero ottenuto.
L'interfaccia è:

codice:
public interface Tree<E> {
public int size();
// ritorna il numero di nodi presenti nell'albero
public String toString();
// stampa l'albero, un elemento per riga, utilizzando una
visita poreorder
public E[] preorder();
// ritorna un array contenente tutti i nodi dell'albero ordinati
in base ad una visita preorder
public E[] inorder();
// ritorna un array contenente tutti i nodi dell'albero ordinati
in base ad una visita inorder
}
Ora, io ho pensato di realizzare l'albero con array, praticamente contiene elementi di tipo TNode, a sua volta di tipo Tripla. Quindi la classe TNode lavorerà con dei parametri che sono indice, che indicano la posizione nell'array del fratello, genitore, eccetera.
Riporto tutte le classi, ma il problema si presenta nella classe Albero nel toString, dove c'è un NullPointerException.

classe Tripla

codice:
public class Triple<E>
{
	int primo, secondo, terzo;

	public Triple(int primo, int secondo, int terzo)
	{
		this.primo=primo;
		this.secondo=secondo;
		this.terzo=terzo;
	}
	
	public int getPrimo(){return primo;}
	
	public int getSecondo(){return secondo;}
	
	public int getTerzo(){ return terzo;}
	
	public void setPrimo(int primo){this.primo=primo;}
	
	public void setSecondo(int secondo){this.secondo=secondo;}
	
	public void setTerzo(int terzo){this.terzo=terzo;}
	
	public String toString()
	{
		return "("+getPrimo()+","+getSecondo()+","+getTerzo()+")";
	}
	
}
[code]

class TNode

codice:
public class TNode<E>
{
	private Triple<E> element;
	private int sons;
	private int firstSon;
	private int sibling;
	private int parent;
	private int level;

	public TNode(Triple<E> element)
	{
		this.element=element;
		sons=0;
		firstSon=-1;
		sibling=-1;
		parent=-1;
		level=-1;
	}
	
	public Triple<E> getElement(){return element;}
	
	public int getSons(){return sons;}
	
	public void setfirstSon(int firstSon){this.firstSon=firstSon;}
	
	public int getfirstSon(){return firstSon;}
	
	public void setsibling(int sibling){this.sibling=sibling;}
	
	public int getsibling(){return sibling;}
	
	public int getparent(){return parent;}
	
	public void setparent(int i){parent=i;}
	
	public void increasesons(){sons++;}
	
	public void setlevel(int level){this.level=level;}
	
	public int getlevel(){return level;}
}
il Main

codice:
import java.io.*;
import java.util.StringTokenizer;

public class Main
{
	public static void main(String [] args)
	{
		Main main=new Main();
		long start=System.currentTimeMillis();
		main.TreeBuilding("input.txt","output.txt");
		long end=System.currentTimeMillis();
		System.out.println("Il tempo d'esecuzione del programma è "+(end-start)+" ns");
	}
	
	public void TreeBuilding(String input, String output)
	{
	   PrintWriter out=null;
	   FileReader reader=null;
	   BufferedReader buff=null;
	   StringTokenizer str=null;
		
		try{
			out=new PrintWriter(output);
			reader=new FileReader(input);
			buff=new BufferedReader(reader);
	
			String current="";
			
			current=buff.readLine();          //tripla corrente
			int altezza=current.charAt(0);  //i primi dati che leggerò saranno questi
			int figli=current.charAt(2);
			int nodi=0;
			
			
			while(buff.ready()){
				current=buff.readLine();         //faccio la lettura per contare quanti nodi ci sono
				nodi++;
			}
			
			Albero<TNode> albero=new Albero(altezza, nodi); 
			
			reader=new FileReader(input);
			buff=new BufferedReader(reader);       //reinizializzo e faccio una prima lettura perchè la prima stringa non mi serve
			buff.readLine();
			
			while(buff.ready()){  
				current=buff.readLine();              //memorizzo la stringa corrente
				
				str=new StringTokenizer(current, "(,)");
				int primo=Integer.parseInt(str.nextToken());            
				int secondo=Integer.parseInt(str.nextToken());
				int terzo=Integer.parseInt(str.nextToken());
				
				Triple tripla=new Triple(primo, secondo, terzo);
		
				
				TNode nodo=new TNode(tripla);
				
				albero.addNode(nodo);
			}
			
			
		    out.print(albero.toString());
	          }
		    
		    catch(FileNotFoundException e1)
		    {
			    System.out.println("Error...file not found");
		    }
		    
		    catch(IOException e2)
		    {
			    System.out.println("Error...input/output");
		    }
		    
		finally{
			
			try{
			    reader.close();
			    buff.close();
			    out.close();
			}
		    
		    catch(IOException e4)
		    {
			    System.out.println("Error...it is not possible to close files");
		    }
	    }

	}
}
classe Albero

codice:
interface Tree<E> {
public int size();
// ritorna il numero di nodi presenti nell'albero
public String toString();
// stampa l'albero, un elemento per riga, utilizzando una visita postorder
public E[] preorder();
// ritorna un array contenente tutti i nodi dell'albero ordinati in base ad una visita preorder
public E[] inorder();
// ritorna un array contenente tutti i nodi dell'albero ordinati in base ad una visita inorder
}

public class Albero<E> implements Tree<E>
{
	private int size;

	private TNode<E> root;
	
	private int height;
	
	private TNode<E>[] albero;         //vorrei usare un array di tipo TNode<E>
	
	private int nodi;
	
	public Albero(int height, int nodi)     //l'albero avrà la sua altezza e un certo numero di nodi
	{
		size=0;
		root=null;
		albero= new TNode[nodi];
		this.height=height;
	}
	
	public int size(){return size;}
	
	public void addNode(TNode<Triple<E>> nodo){
		
		if(size==0)                       //inserisco la radice 
		{
			root=(TNode<E>)nodo;
			root.setfirstSon(1);       //setto il suo primo figlio
			nodo.setparent(0);        //setto il padre
			root.increasesons();      //incremento il numero di figli
			root.setlevel(0);          //livello della radice
			albero[0]=root;            //inserisco nell'array
			nodo.setlevel(1);         //livello del figlio
			size++;
		}
		
		else{
			
			for(int i=0; i<albero.length; i++)
			{
				if(albero[i]!=null){
					
				if(albero[i].getSons()==0 && albero[i].getlevel()!=height)      //se il nodo non ha figli e non siamo in una foglia
				{
					albero[i].setfirstSon(i+albero[i-1].getfirstSon());       //setto l'inice del primofiglio di albero[i]
					albero[albero[i].getfirstSon()]=(TNode<E>)nodo;                           //setto il figlio
					albero[albero[i].getfirstSon()].setsibling(albero[i].getfirstSon()+1);     //setto l'indice del fratello del figlio......
					albero[albero[i].getfirstSon()].setparent(i);                                      //setto l'indice del padre di questo figlio
					albero[albero[i].getfirstSon()].setlevel(albero[i].getlevel()+1);        //setto il livello del figlio
					albero[i].increasesons();  //incremento il contatore dei figli del nodo di partenza
					size++;
				}
				
				else if(albero[i].getSons()>=1 && albero[i].getSons()<4 && albero[i].getlevel()!=height)  //se il numero dei figli e maggiore uguale ad 1 e minore di 4 ne devo inserire ancora di figli
				{
					int dad=i; //memorizzo l'indice del padre
					
					i=albero[i].getfirstSon();    //indice del figlio
					
					while(albero[i]!=null)    //finchè ci sono figli vai alle altre posizioni
						i++;
					
					albero[i]=(TNode<E>)nodo;               //e poi faccio setto l'elemento, 
					albero[i].setsibling(i+1);        		//il fratello
					albero[i].setparent(dad);			// il genitore
					albero[i].setlevel(albero[dad].getlevel()+1);         //il livello
					albero[i].increasesons();                   //incremento il contatore di figli del nodo di partenza
					size++;
				}
			}
			
			}
		       }
	}
	
	
	public String toString()
	{
		String toReturn="";
		 E[] elemArray = preorder();
		
		for(int i=0; i<elemArray.length; i++)
		toReturn+=elemArray[i].toString()+'\r'+'\n';  //qui c'è l'errore
		
		return toReturn;
	}
		
		
		
	
	public E[] preorder()
	{
		E[] elemArray =(E[]) new Object[size];   //memorizzerà gli elementi dell'albero in un array ordinato secondo la visita preorder
		
		int index=0;
		int i=0;
		int j=0;
		
		elemArray[index]=(E)albero[0];
		
		while(i<albero[0].getSons()-1)
		{
			while(albero[j].getfirstSon()!=-1)
			{
				j=albero[j].getfirstSon();
				elemArray[index++]=(E)albero[j];
			}
			
			while(albero[j].getsibling()!=-1)
				elemArray[index++]=(E)albero[j++];
				elemArray[index++]=(E)albero[j++];  //ultimo fratello da inserire nell'array
			
			i++;
			j=i+1; //l'indice del fratello dei figli della radice;
		}
		
		return elemArray;
		
	}
	
	public E[] inorder(){
		
	 E[] elemArray =(E[]) new Object[size];   //memorizzerà gli elementi dell'albero in un array ordinato secondo la visita inorder
		
		int index=0;
		int i=0;
		int j=0;
		int ultimo=0;
		
		while(i<albero[0].getSons()-1)
		{
			while(albero[j].getfirstSon()!=-1)
				j=albero[j].getfirstSon();
			
			ultimo=j;
			
			while(albero[j].getparent()!=0){
				elemArray[index++]=(E)albero[j];
				j=albero[j].getparent();
			}
			elemArray[index++]=(E)albero[j];
			
			if(i==0) elemArray[index++]=(E)albero[0];
			
			while(albero[ultimo].getsibling()!=-1){
				elemArray[index++]=(E)albero[albero[ultimo].getsibling()];
				ultimo++;
			}
			
			i++;
			j=i+1;
		}
		
		return elemArray;
	}
		
	public E[] postorder(){                            
		
	 E[] elemArray =(E[]) new Object[size];          //memorizzerà gli elementi dell'albero in un array ordinato secondo la visita postorder
		
		int index=0;
		int i=0;
		int j=0;
		
		while(i<albero[0].getSons()-1)
		{
			while(albero[j].getfirstSon()!=-1)
				j=albero[j].getfirstSon();
			
			while(albero[j].getsibling()!=-1)
				elemArray[index++]=(E)albero[j++];
				elemArray[index++]=(E)albero[j];
			
				elemArray[index++]=(E)albero[albero[j].getparent()];
			
			i++;
			j=i+1;
		}
		
		return elemArray;
		
	}
}
Ecco gli errori:

codice:
Exception in thread "main" java.lang.NullPointerException
	at Albero.toString(Albero.java:94)
	at Main.TreeBuilding(Main.java:63)
	at Main.main(Main.java:10)
>Exit code: 1
Sbaglio forse l'inseirmento, non so dove mettere mani sinceramente, temo ci siano molte cose pensate male...mi aiutereste?

Grazie.