AVL Tree

Status
Niet open voor verdere reacties.

MouNtant

Gebruiker
Lid geworden
2 jul 2011
Berichten
42
Hallo,

Ik probeer nu al enige tijd een AVL tree te maken en ik vindt het best lastig. Ik begrijp het idee erachter alleen krijg het moeilijk omgezet naar code ;)

Ik heb een gewoon binary tree gemaakt. Deze heeft een add, remove find etc functies. Ik wil deze dan ombouwen of verbouwen ;) naar een AVL tree.

Ik heb al belachelijk veel doc's gelezen, maar ik snap niet helemaal het principe van -1, 0, 1. Ik had eigenlijk de hoop opgegeven en wilde gewoon de height opslaan in de nodes. Toch dacht ik laat ik het vragen misschien weet iemand het wel!

Ik heb alle rotations al geprogrammeerd. Dat was opzicht best makkelijk en te begrijpen. Kan ze alleen nog niet toepassen ;) Wat ik eigenlijk wil zeggen/vragen is:

1. Hoe werkt die -1, 0 ,1?
2. Hoe insert ik een item?
3. Heeft er iemand goede doc's voor AVL tree?

Wat ik al heb:
binary tree werkend, dus enige kennis is er ;)

gr Mount!
 
AVL Tree iets verder

Hey,

Snap je antwoord niet helemaal. Maar wat ik nu heb is dat elke node een height heeft die ik met elkaar kan vergelijken en hij detecteert dan ook of de boom niet goed is. Deze code maakt een gewonen binary boom. Hij is dus nog niet AVL maar hij kijkt wel met de juiste test data dat de boom niet in balans is. Dat zie je in de insert functie waar ik deze test alleen nog maar in rechter kant heb geimplementeerd. Wat ik nu heb doet de rotatie goed en returnd dat de goede node maar hoe wordt die node de nieuwe root?

Ik ben het helemaal kwijt :) hoop dat iemand het ziet!

gr Mount

Dit is me Node klassen:

Code:
package iad4.AVL;

public class AvlNode<E>
{ 
	private E element;     
	private AvlNode<E>    left;         
	private AvlNode<E>    right;
	private AvlNode<E>	  parent;
	private int       	  height;
	
	private static StringBuffer  buffer;
			
	public AvlNode(  )
    {
		setElement( null );
		setHeight( -1 );
    }

    public AvlNode( E theElement )
    {
        setElement(theElement);
        setLeft( null );
        setRight( null );
        setParent( null );
        setHeight( 0 );
    }
    
    /*
	 * This method is so that the user doesn't have to add the root evertime,
	 * only the newChild.
	 */ 
    public void add( AvlNode<E>x )
    {
        insert( x, this );
    }
    
    /*
	 * This method does the added. It checks if the node is bigger or smaller then the current.
	 * This happens with the compare method which the adding node should have. It runs recursief
	 * until it hits a leaf, then it adds itself.
	 */
    private void insert( AvlNode<E>newChild, AvlNode<E> root )
    {       
        if(((Comparable<E>) newChild.getElement()).compareTo( root.getElement() ) < 0 )
        {
        	if(root.getLeft() == null)
			{
				root.setLeft( newChild );
				newChild.setParent( root );
				System.out.println("Added left " + ((Digit) newChild.getElement()).getNumber() );
			}
			else
				insert(newChild, root.getLeft());
        }
        else if( ((Comparable<E>) newChild.getElement()).compareTo( root.getElement() ) > 0 )
        {
  			if(root.getRight() == null)
  			{
				root.setRight( newChild );
				newChild.setParent( root );
				System.out.println("Added Right " + ((Digit) newChild.getElement()).getNumber() );
	  			
				if( height( this.getRight() ) - height( this.getLeft()) > 1 )
		    	{
					System.out.println("Unbalanced");
					root = adjustRightTree(root);
		    	}

			}
			else
				insert(newChild, root.getRight());
  			
        }
        else{
        	System.out.println("Duplicate");
        	;
        }
    	root.setHeight(height(root));     
    }

    public AvlNode<E> adjustRightTree(AvlNode<E> node)
    {
        System.out.println("Unbalanced right!, node which is the ****er: " + ((Digit) node.getElement()).getNumber());
        AvlNode<E> root = rotateWithRightChild(node.getParent());
            
        System.out.println(root.preOrderToString());
        return root;
    }
    
	/*
	 * This methods runs through the entire tree preOrder style.
	 * When its done it returns a Stringbuffer containing all the numbers
	 * in the tree
	 */
	public String preOrderToString()
	{
		buffer = new StringBuffer();
		buffer.append("Root: " );
		preOrder();
		return buffer.toString();
	}
	
	private void preOrder()
	{
		buffer.append(((Digit) getElement()).getNumber() + " Height: " + getHeight() + " ");
		if( getLeft() != null )
		{
			buffer.append("Left: ");
			getLeft().preOrder();
		}
		if( getRight() != null )
		{
			buffer.append("Right: ");
			getRight().preOrder();
		}
	}
    
    /*
	 * This method return the height of a given node. With this
	 * method i can check if the tree is balanced
	 */
	public int height(AvlNode<E> node)
	{
		int heightLeft = 0;
		int heightRight = 0;
		
		if (node == null)
            return -1;
		
		if(node.getLeft() != null)
			heightLeft = height(node.getLeft())  + 1;
		if(node.getRight() != null)
			heightRight = height(node.getRight()) + 1;
        return Math.max(heightLeft, heightRight);    
	}

	/*
	 * Rotate a binary tree node with his left child. For AVL trees, this
	 * is a single rotation for case 1.
	 */
	private AvlNode<E> rotateWithLeftChild( AvlNode<E> k2 )
	{
		AvlNode<E> k1 = k2.getLeft();
		k2.setLeft(k1.getRight());
		k1.setRight( k2 );
		return k1;
	}
	
	/*
	 * Double rotate binary tree node: first left child with its right child;
	 * then node k3 with new left child. For AVL trees, this is a double rotation
	 * for case 2.
	 */
	private AvlNode<E> doubleRotateWithLeftChild( AvlNode<E> k3 )
	{
		k3.setLeft(rotateWithRightChild( k3.getLeft()));
		return rotateWithLeftChild( k3 );
	}
	
	/*
	 * Double rotate binary tree node: first right child with its left child;
	 * then node k1 with new right child. For AVL trees, this is a double rotation
	 * for case 3.
	 */
	private AvlNode<E> doubleRotateWithRightChild( AvlNode<E> k1 )
	{
		k1.setRight( rotateWithLeftChild( k1.getRight() ));
		return rotateWithRightChild( k1 );
	}
	
	/*
	 * Rotate binary tree node with right child. For AVL trees this is a
	 * single rotation for case 4.
	 */
	private AvlNode<E> rotateWithRightChild( AvlNode<E> k1)
	{
		AvlNode<E> k2 = k1.getRight();
		k1.setRight( k2.getLeft() );
		k2.setLeft( k1 );
		return k2;
	}

    
    /*
     * Getters And setters!
     */
   ... Niet interressant
}

Me Main:
Code:
package iad4.AVL;

public class MainAVL
{
	public MainAVL()
	{
		AvlNode<Digit> root = new AvlNode<Digit>( new Digit( 50 ));
		AvlNode<Digit> node1 = new AvlNode<Digit>( new Digit( 51 ));
		AvlNode<Digit> node2 = new AvlNode<Digit>( new Digit( 52 ));
		//AvlNode<Digit> node3 = new AvlNode<Digit>( new Digit( 49 ));

		root.add( node1 );
		root.add(node2);
		//root.add(node3);
		
		System.out.println(root.preOrderToString());
	}
	public static void main(String[] args)
	{
		new MainAVL();
	}

}

En nog een digit klassen die comparable is, maar dat is niet zo interresant
 
Als je de complete source hebt, dan wil ik er wel even naar kijken. Heb zelf nog nooit een AVLtree gemaakt maar heb genoeg ervaring met binary trees, misschien dat ik er uit kom ?
 
Sorry voor de insane late reactie. Ik had veel deadline's voor projecten nog staan ;)

Helaas moet ik echt een AVL tree maken.

Om dit probleem op te lossen ben ik eerst nog terug gegaan naar de binary tree. Ik had een tree die een specefieke node moest krijgen bij mij was dit een digit. Ik wil hem ombouwen dat hij alles accepteerd als het maar kan comparen. Volgens mij heb ik hem werkend maar er staat toch nog een foutje in.

Fout: Unchecked cast, is al eerder gevraagd door mij maar nu geef ik al me code

Code:
package iad4;


public class BinaryNode<E>
{ 
	private E 				 element;     
	private BinaryNode<E>    left;         
	private BinaryNode<E>    right;
	private BinaryNode<E>	 parent;
	
	private static StringBuffer  buffer;
			
	public BinaryNode(  )
    {
		setElement( null );
    }

    public BinaryNode( E theElement )
    {
        setElement(theElement);
        setLeft( null );
        setRight( null );
        setParent( null );
    }
    
    /*
	 * This method is so that the user doesn't have to add the root evertime,
	 * only the newChild.
	 */ 
    public void add( BinaryNode<E>x )
    {
        insert( x, this );
    }
    
    /*
	 * This method does the added. It checks if the node is bigger or smaller then the current.
	 * This happens with the compare method which the adding node should have. It runs recursief
	 * until it hits a leaf, then it adds itself.
	 */
    private void insert( BinaryNode<E>newChild, BinaryNode<E> root )
    {       
        if(((Comparable<E>) newChild.getElement()).compareTo( root.getElement() ) < 0 )
        {
        	if(root.getLeft() == null)
			{
				root.setLeft( newChild );
				newChild.setParent( root );
				System.out.println("Added left " + ((Digit) newChild.getElement()).getNumber() );
			}
			else
				insert(newChild, root.getLeft());
        }
        else if( ((Comparable<E>) newChild.getElement()).compareTo( root.getElement() ) > 0 )
        {
  			if(root.getRight() == null)
  			{
				root.setRight( newChild );
				newChild.setParent( root );
				System.out.println("Added Right " + ((Digit) newChild.getElement()).getNumber() );
			}
			else
				insert(newChild, root.getRight());
  			
        }
        else{
        	System.out.println("Duplicate");
        	;
        }
    }

Bij dit stuk:
if(((Comparable<E>) newChild.getElement()).compareTo( root.getElement() ) < 0 )

Geeft hij een unchecked cast from E to comparable<E>. Eclipse geeft het wel als oplossing want zonder doet hij het niet. Hoe fix ik dit ik erger me dood aan :P. Het programma werkt en doet wat het moet doen maar ik wil dit snappen. Ga ik te ver met casten of wat?

Hoop dat jullie het weten!
 
Laatst bewerkt:
Elke object moet een compare to hebben en moet compareble java.lang implementeren
Dit maakt dat je het object kan vergelijken met een ander object

Maar mogelijks ga je niet willen vergelijken met het object Object omdat elk object een instantie van Object is.
Je kan als parameter dan (indien je het nuttig wil maken ) vergelijken met het eigen object maar ook met de vader (die wordt dan overgeerft van het vaderobject)
Je kan ook de parameter met een interface maken dit maakt mogelijk dat je objecten die voldoen aan eenzelfde interface kan vergelijken.Dit lijkt raar maar als je objecten in een collectie stopt wil je weten voor je cast of je wel met een dergelijk object te doen hebt voor je iets wil doen

Met andere woorden
Aan een object auto kan vragen om de deur open te doen
en aan een object huis kan je ook vragen om de deur open te doen
en toch is een verschil ook al bezitten ze een object deur en een getdeur.
 
Hey

Bedankt voor het reageren. Ik snap je antwoord niet echt en heb nog niet een idee hoe ik het kan oplossen, misschien iets verduidelijking met wat pseudo code ofso als je de tijd hebt.


gr MouNt
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan