This is the code for AVL tree. You need to fill in the code for insert that calls balancing methods. You also need to fill in the code for the balancing methods (one in class, and the remaining three in the problem set).

public class AVLNode {
    private AVLNode left, right;
    private Comparable data;
    private int leftHeight;
    private int rightHeight;
    private AVLTree tree; //the tree that the node belongs to
    // true if running in a testing mode, false otherwise
    // if false, no priting will be done
    private boolean testing = true;
    
    public AVLNode(Comparable data, AVLTree tree){
	this.data = data;
	this.tree = tree;
    }
    
    public AVLNode getLeft(){
	return left;
    }
    
    public AVLNode getRight(){
	return right;
    }

    public void setLeft(AVLNode left){
	this.left = left;
    }

    public void setRight(AVLNode right){
	this.right = right;
    }
    
    public Comparable getData() {
	return data;
    }

    public void inOrder() {
	if (left != null) left.inOrder();
	System.out.println(data);
	if (right != null) right.inOrder();    
    }

    public void preOrder() {
	System.out.println(data);
	if (left != null) left.preOrder();	
	if (right != null) right.preOrder();    
    }    
    
    public int getBalance() {
	// the absolute value of the height difference
	return Math.abs(leftHeight - rightHeight);
    }

    // recursive insert. Takes a parent node. Returns the height of the 
    // tree rooted at this node
    // Performs all necessary rebalancing 
    public int insert(Comparable data, AVLNode parent) {
	if (data.compareTo(this.data) < 0) {
	    if (left != null) { 
		leftHeight = left.insert(data, this);
	    } else {
		// left is null, inserting the node at the left
		left = new AVLNode(data, tree);
		leftHeight = 1;
	    }
	} else {
	    if (right != null) {
		rightHeight = right.insert(data, this);
	    } else {
	    // right is null, inserting the node at the right
		right = new AVLNode(data, tree);
		rightHeight = 1;
	    }
	}
	// rebalance the tree if needed
	if (getBalance() == 2) {
	    testPrint("Need to rebalance");
	    // figure out which of the four cases take place
	    if (data.compareTo(this.data) < 0) {
		testPrint("data = " + data + " this.data = " + 
				   this.data + " left.data " + left.getData());
		// if the data was inserted to the left
		if (data.compareTo(left.getData()) < 0) {
		    // single R rotation
		    testPrint("single R");
		    return singleR(data, parent);
		} else {
		    // zigzag: LR rotation
		    testPrint("double LR");
		    return doubleLR(data, parent);
		}
	    } else {
		// if the data was inserted to the right
		if (data.compareTo(right.data) > 0) {
		    // single L rotation
		    testPrint("single L");
		    return singleL(data, parent);
		} else {
		    // zigzag: RL rotation
		    testPrint("double RL");
		    return doubleRL(data, parent);
		}
	    }
	}
        return 1 + Math.max(leftHeight,rightHeight);
    }

    // performs a single right rotation 
    // returns the height of the new subtree
    // Assume that this is the rotation that needs to be performed
    private int singleR(Comparable data, AVLNode parent) {
    	// saving away a reference to the left node
	AVLNode myleft = left;

	// rearranging the tree 
	left = left.right;
	myleft.right = this;
	// resetting the heights of the changed nodes
	leftHeight = myleft.rightHeight;
	myleft.rightHeight = Math.max(leftHeight, rightHeight) + 1;

	// if this node is not the root, reset the parent's 
	// reference and height
	if (parent != null) {
	    // we don't know if this node is the left child of its parent or 
	    // the right one, need both cases
	    if (parent.left == this) {
		// if this node is the left child of its parent
		parent.left = myleft;	
		parent.leftHeight = Math.max(myleft.leftHeight, 
					     myleft.rightHeight) + 1;
	    } else {
		// this node is the right child of its parent
		parent.right = myleft;
		parent.rightHeight = Math.max(myleft.leftHeight, 
					      myleft.rightHeight) + 1;
	    }
	} else {
	    // this node is the root, has no parent
	    // need to reset the root reference of the tree
	    tree.setRoot(myleft);
	}
	// the height of the tree rooted at myleft (new root)
	return 1 + Math.max(myleft.leftHeight,myleft.rightHeight);
    }

    private int singleL(Comparable data, AVLNode parent) {
	// this stub needs to be replaced by real code
	// now it returns the height of the tree rooted at this node
	return 1 + Math.max(leftHeight,rightHeight);
    }

    private int doubleLR(Comparable data, AVLNode parent) {
	// this stub needs to be replaced by real code
	// now it returns the height of the tree rooted at this node
	return 1 + Math.max(leftHeight,rightHeight);
    }

    private int doubleRL(Comparable data, AVLNode parent) {
	// this stub needs to be replaced by real code
	// now it returns the height of the tree rooted at this node
	return 1 + Math.max(leftHeight,rightHeight);
    }

    // prints only when in testing mode
    private void testPrint(String s) {
	if (testing) {
	    System.out.println(s);
	}
    }
}



public class AVLTree {
    private AVLNode root;
    
    public AVLTree() {
    }
    
    public boolean isEmpty() {
	return (root == null);
    }
    
    public AVLNode getRoot(){
	return root;
    }
    
    public AVLNode search(Comparable data) {
        AVLNode node = root;

        while (node != null && data.compareTo(node.getData()) !=  0){
            if (data.compareTo(node.getData()) < 0){
                node = node.getLeft();
            } else {
                node = node.getRight();
            }
        }
        return node;
    }
 
    // recursive insert
    public int insert(Comparable data) {
	if (root == null) {
	    root = new AVLNode(data, this);
	    return 1;
	} 
	return root.insert(data, null);
    }

    public void setRoot(AVLNode newroot) {
	root = newroot;
    }
	
    public void inOrder() {
        if (root != null) root.inOrder();
    }

    public void preOrder() {
        if (root != null) root.preOrder();
    }
}




public class AVLTest {
    public static void main(String [] args) {
	AVLTree avl = new AVLTree();
	String [] strings = {"tomatoes", "strawberries","oranges", "kiwi", "apples"
	    //"grapes", "cucumbers", "apples", "kiwi", "tomatoes"
	    //"strawberries", "bananas", "oranges",  
	    //"pumpkins"
	};

	for (int i = 0; i < strings.length; ++i) {
	    System.out.println(avl.insert(strings[i]));
	}

	System.out.println("In-order:");
	avl.inOrder();

	System.out.println("Pre-order:");
	avl.preOrder();
    }

}


This is an example from CSci 2101 course.