views:

627

answers:

2
+3  Q: 

AVL Tree Balancing

Hello, I am working on an assignment that asks me to implement an AVL tree. I'm pretty sure I have the rotation methods correct, but I'm having trouble figuring out when to use them.

For example, the explanation in the book says that I should climb up the same path I went down to insert the node/element. However, I can't have any parent pointers.

Latest code:

public BinaryNode<T> insert(BinaryNode<T> node) {
    if (this.getElement().compareTo(node.getElement()) > 0) {
        if (this.getLeftChild() != null) {
            BinaryNode<T> b = this.getLeftChild().insert(node);

            if(!this.isBalanced()) {
                this.balance();
            }

            return b;
        } else {
            this.setLeftChild(node);
        }

    } else if (this.getElement().compareTo(node.getElement()) < 0) {
        if (this.getRightChild() != null) {
            return this.getRightChild().insert(node);
        } else {
            this.setRightChild(node);
        }
    }

    return this;
}

What I want to do here is climb back up the tree, but it can only check the balancing AFTER it inserts the node. Hence, this being in the else clause.

I also tried putting the balance code where R Samuel Klatchko suggested, but checked the balance on each insert. For example: If one inserts 7, 9, 5, 3, and 1 consecutively, I get a null pointer exception when trying to insert 1.

EDIT: One reason for the above may have something to do with the way I was doing the height. It works fine with a single right rotation if I calculate the height every time with height() but that breaks the O(log(n)) time of an AVL Tree.

Any thoughts on how to accomplish this?

Thanks.

+1  A: 

You might try passing the parent pointer into the insert method, or you could convert insert into an iterative method and keep an explicit stack on which you record the path down the tree.

By the way, in order to choose which rotation to use, you can just know that a node is unbalanced, you have to know whether the deeper subtree is on the right or on the left. This means that your simple isBalanced method isn't quite enough. It's also inefficient, and will blow the AVL tree's O(log n) complexity, because you compute the heights each time.

Dale Hagglund
Yeah, I'm aware of the height issue. That's something minor I can fix later. I also plan on adding a method to tell which child is taller or in other words violates the AVL balance property.
linuxlover101
Any idea how to detect whether an unbalanced node needs a single or double rotation?
linuxlover101
http://en.wikipedia.org/wiki/AVL_tree tries to give an overview of how to choose the rotations. I'd suggest starting there, and perhaps finding a description of the algorithm in a textbook or other paper.
Dale Hagglund
+2  A: 

You code is climbing up the same path you went down. Consider this code:

if (this.getLeftChild() != null) {
    return this.getLeftChild().insert(node);
} 

and modify it slightly:

if (this.getLeftChild() != null) {
    boolean b = this.getLeftChild().insert(node);
    // do something here
    return b;
} 

As the code returns from the recursive calls, each return brings you back to the parent. By not immediately returning the value of the recursive call, you have a chance to do your rebalancing.

Update for latest code

Don't forget to rebalance when you've inserted to the right.

R Samuel Klatchko
So is that where I should put my balancing algorithm? Not right after I actually insert the node?I think my confusion is coming from a lack of full understanding of the recursion that's happening here.
linuxlover101
So I tried out an implementation similar to the above and it's checking the balance when going up and down. Is there a way to check it only when going up?
linuxlover101
Please update the question with your latest code (and add in a comment so I know when to review).
R Samuel Klatchko
I added the latest code I tried and some information.
linuxlover101