如何获得AVL树的高度?

时间:2018-12-08 14:13:24

标签: avl-tree

这是我的AVL树类:

    public class AVLTree1 {

    // Each AVLtree object is (a header of) an AVL-tree.
    // This AVL-tree is represented simply by a reference to its root node (root).
    private Node root;

    public AVLTree1 () {
    // Construct an empty AVL-tree.
        this.root = null;
    }

//    public size () {
//    // Return the size (i.e., number of elements) of this AVL-tree.
//        return sizeOfSubtree(root);
//    }

    public Node search (Comparable target) {
    // Find which if any node of this AVL-tree contains an element equal to target. 
    // Return a link to that node (or null if there is none).
        int direction = 0;  // ... 0 for here, < 0 for left, > 0 for right
        Node curr = this.root;
        for (;;) {
            if (curr == null)
                return null;
            direction = target.compareTo(curr.element);
            if (direction == 0)
                return curr;
            if (direction < 0)
                curr = curr.left;
            else  // direction > 0
                curr = curr.right;
        }
    }

    public void insert (Comparable elem) {
    // Insert the element elem in this AVL-tree.
        Node ins = insertBST(elem);
        if (ins != null)
            rebalance(ins);
    }

    private Node insertBST (Comparable elem) {
    // Insert the element elem in this AVL-tree, treating it as an ordinary
    // binary search tree. Return a link to the newly-inserted leaf node, or null
    // if no node was inserted.
        int direction = 0;  // ... 0 for here, < 0 for left, > 0 for right
        Node parent = null, curr = root;
        for (;;) {
            if (curr == null) {
                Node ins = new Node(elem, parent);
                if (root == null)
                    root = ins;
                else {
                    if (direction < 0)
                        parent.left = ins;
                    else  // direction > 0
                        parent.right = ins;
                }
                return ins;
            }
            direction = elem.compareTo(curr.element);
            if (direction == 0)
                return null;
            parent = curr;
            if (direction < 0)
                curr = curr.left;
            else  // direction > 0
                curr = curr.right;
        }
    }

    private Node deletee = null;  // link to node just deleted
                                  // (accessed only by delete and auxiliary methods)

    public void delete (Comparable elem) {
    // Delete the element elem from this AVL-tree.
        deleteBST(elem);
        if (deletee != null) {
            rebalance(deletee);
            deletee = null;
        }
    }

    private void deleteBST (Comparable elem) {
    // Delete the element elem in this AVL-tree, treating it as an ordinary
    // binary search tree.
        int direction = 0;  // ... 0 for here, < 0 for left, > 0 for right
        Node curr = this.root;
        for (;;) {
            if (curr == null)
                return;
            direction = elem.compareTo(curr.element);
            if (direction == 0) {
                Node modified = deleteTopmost(curr);
                Node parent = curr.parent;
                if (curr == this.root)
                    this.root = modified;
                else if (curr == parent.left)
                    parent.left = modified;
                else  // curr == parent.right
                    parent.right = modified;
                if (modified != null)  modified.parent = parent;
                return;
            }
            if (direction < 0)
                curr = curr.left;
            else  // direction > 0
                curr = curr.right;
        }
    }

    private Node deleteTopmost (Node top) {
    // Delete the topmost element in the subtree whose topmost node is top.
    // Return a link to the modified subtree.
        if (top.left == null) {
            deletee = top;
            return top.right;
        } else if (top.right == null) {
            deletee = top;
            return top.left;
        } else {  // top has both a left child and a right child
            top.element = top.right.getLeftmost();
            top.right = deleteLeftmost(top.right);
            return top;
        }
    }

    private Node deleteLeftmost (Node top) {
    // Delete the leftmost node of the (nonempty) subtree
    // whose topmost node is top.
    // Return a link to the modified subtree.
        Node curr = top;
        while (curr.left != null)
            curr = curr.left;
        deletee = curr;
        if (curr == top)
            return top.right;
        else {
            curr.parent.left = curr.right;
            return top;
        }
    }




    private void rebalance (Node node) {
    // Rebalance this AVL-tree, following insertion or deletion of node.
        Node ancestor = node;
        while (ancestor != root) {
            ancestor = ancestor.parent;
            ancestor.setHeight();
            if (! ancestor.isHeightBalanced()) {
                Node greatAncestor = ancestor.parent;
                Node rotated = rotate(ancestor);
                if (ancestor == root)
                    setRoot(rotated);
                else if (ancestor == greatAncestor.left)
                    greatAncestor.setLeft(rotated); 
                else  // ancestor == greatgrandparent.right
                    greatAncestor.setRight(rotated);
                ancestor = rotated;
            }
        }
    }

    private Node rotate (Node grandparent) {
    // Rotate the node grandparent, the node parent (grandparent's higher child),
    // and the node child (parent's higher child).
    // After an insertion, all three nodes are ancestors of the inserted node.
    // After a deletion, only grandparent is an ancestor of the deleted node.
        Node parent = grandparent.higherChild();
        Node child = parent.higherChild();
        Node a, b, c;
        Node t1, t2, t3, t4;
        if (child == parent.left && parent == grandparent.left) {
            a = child;  b = parent;  c = grandparent;
            t1 = child.left;  t2 = child.right;
            t3 = parent.right;  t4 = grandparent.right;
        } else if (child == parent.right && parent == grandparent.left) {
            a = parent;  b = child;  c = grandparent;
            t1 = parent.left;  t2 = child.left;
            t3 = child.right;  t4 = grandparent.right;
        } else if (child == parent.right && parent == grandparent.right) {
            a = grandparent;  b = parent;  c = child;
            t1 = grandparent.left;  t2 = parent.left;
            t3 = child.left;  t4 = child.right;
        } else {  // child == parent.left && parent == grandparent.right
            a = grandparent;  b = child;  c = parent;
            t1 = grandparent.left;  t2 = child.left;
            t3 = child.right;  t4 = parent.right;
        }
        print();
        System.out.println("... now rebalancing"
                + " a = " + a.element
                + " b = " + b.element
                + " b = " + c.element);
        a.setLeft(t1);  a.setRight(t2);  a.setHeight();
        c.setLeft(t3);  c.setRight(t4);  c.setHeight();
        b.setLeft(a);   b.setRight(c);   b.setHeight();
        return b;
    }

    private void setRoot (Node newRoot) {
    // Make newRoot this AVL-tree's root node.
        this.root = newRoot;
        newRoot.parent = null;
    }

    //////////// Driver ////////////

    public void print () {
    // Print a textual representation of this AVL-tree.
        printSubtree(root, "");
    }

    private static void printSubtree (Node top, String indent) {
    // Print a textual representation of the subtree of this AVL-tree whose
    // topmost node is top, indented by the string of spaces indent.
        if (top == null)
            System.out.println(indent + "o");
        else {
            System.out.println(indent + "o-->");
            String childIndent = indent + "    ";
            printSubtree(top.right, childIndent);
            System.out.println(childIndent + top.element + " (" + top.height + ")"
                    + (top.parent == null ? "" : " parent " + top.parent.element.toString()));
            printSubtree(top.left, childIndent);
        }
    }



    //////////// Inner class ////////////

    public static class Node {

        // Each Node object is an AVL-tree node.
        // This node is represented by its element (element) together with
        // references to its left child (left), its right child (right), and
        // its parent (parent), and its height (height).
        // For every element x stored in the subtree at left:
        //    x.compareTo(element) < 0
        // For every element y stored in the subtree at right:
        //    y.compareTo(element) > 0
        private Comparable element;
        private Node left, right, parent;
        private int height;

        public Node (Comparable elem, Node parent) {
        // Construct an AVL-tree node with element elem and no children.
            this.element = elem;
            this.left = null;
            this.right = null;
            this.parent = parent;
            this.height = 0;
        }

        private Comparable getLeftmost () {
        // Return the element in the leftmost node of the (nonempty) subtree
        // whose topmost node is this.
            Node curr = this;
            while (curr.left != null)
                curr = curr.left;
            return curr.element;
        }

        private static int sizeOfSubtree (Node top) {
        // Return the size of the subtree whose topmost node is top.
            if (top == null)
                return 0;
            else
                return 1 + sizeOfSubtree(top.left) + sizeOfSubtree(top.right);
        }

        private void setLeft (Node child) {
        // Make child the left child of this node.
            left = child;
            if (child != null)  child.parent = this;
        }

        private void setRight (Node child) {
        // Make child the right child of this node.
            right = child;
            if (child != null)  child.parent = this;
        }

        private void setHeight () {
        // Recompute the height of this node (assuming that the heights of its
        // children are accurate).
            height = Math.max(getHeight(left), getHeight(right)) + 1;
        }

        public static int getHeight (Node node) {
        // Return the height of node.
            return (node == null ? -1 : node.height);
        }

        private Node higherChild () {
        // Return the child of this node with the greater height.
        // If the heights are equal, return either child.
            return (getHeight(left) >= getHeight(right) ? left : right);
        }

        private boolean isHeightBalanced () {
        // Return true if and only if this node is height-balanced, i.e.,
        // the heights of its children differ by at most one.
            int balance = getHeight(left) - getHeight(right);
            return (balance >= -1 && balance <= +1);
        }

    }

}

我需要一个函数来计算这棵树的高度。如何获得AVL树的高度?

1 个答案:

答案 0 :(得分:0)

要获取任何二叉树的高度,您可以通过以下两种方式之一进行:

  1. 没有在节点中添加属性:(伪代码)

    getHeight(Node)
    
        if node is leafnode then return 1;
    
        if node has one child, then return getHeight(left/right node)+1
    
        if node has 2 children, then return max(getHeight(left node), getHeight(right node))+1;
    

2 或者,您可以向 Node 添加一个名为 height 的属性,然后该方法将如下所示:

 getHeight(Node)
 
     if node is leafnode then return 1;
     
     if node has one child, get that child's height value+1

     if node has 2 child, get max(left child's height, right child's height)

第一种方法每次都递归计算高度。您不需要维护一个额外的属性,但如果树变得非常大,您确实会面临堆栈溢出的风险。

对于第二种方法,您永远不需要担心堆栈溢出,但是在从树中插入和删除时确实需要做一些额外的工作。您需要在插入/删除过程中更新您访问过的每个节点的高度值。