AVL树java实现代码

/* 
 * 文 件 名:  AVLTree.java 
 * 修改时间:  2012-11-30 
 */
package tree;

/**
 * AVL树
 * 
 * @version [版本号, 2012-11-30]
 */
public class AVLTree
{
    /**
     * AVL树的根节点
     */
    private AVLNode root;
    
    /**
     * <默认构造函数>
     */
    public AVLTree()
    {
        root = null;
    }
    
    /**
     * 判断树是否为空
     * 
     * @return
     * @see [类、类#方法、类#成员]
     */
    public boolean isEmpty()
    {
        return root == null;
    }
    
    /**
     * 查找指定关键字的插入位置,小于插左边,大于或者等于插右边
     * 
     * @return
     * @see [类、类#方法、类#成员]
     */
    public AVLNode findInsert(int data)
    {
        AVLNode current = root;
        while (current != null)
        {
            if (data < current.data)
            {
                if (current.left == null)
                {
                    break;
                }
                else
                {
                    current = current.left;
                }
            }
            else
            {
                if (current.right == null)
                {
                    break;
                }
                else
                {
                    current = current.right;
                }
            }
        }
        return current;
    }
    
    /**
     * AVL树插入操作,最重要的操作
     * 
     * @param data
     * @see [类、类#方法、类#成员]
     */
    public void insert(int data)
    {
        // 新建一个节点
        AVLNode insertNode = new AVLNode(data);
        // 如果根节点为空,直接赋值给根节点
        if (root == null)
        {
            root = insertNode;
            return;
        }
        AVLNode insertPos = root;
        // 先将节点插入树中,需要回朔改变插入路径的各个节点的平衡因子。
        while (insertPos != null)
        {
            if (data < insertPos.data)
            {
                if (insertPos.left == null)
                {
                    insertPos.left = insertNode;
                    insertPos.bf += 1;
                    insertNode.parent = insertPos;
                    break;
                }
                else
                {
                    insertPos = insertPos.left;
                }
            }
            else
            {
                if (insertPos.right == null)
                {
                    insertPos.right = insertNode;
                    insertPos.bf -= 1;
                    insertNode.parent = insertPos;
                    break;
                }
                else
                {
                    insertPos = insertPos.right;
                }
            }
        }
        // 下面是回朔算法,从insertPos节点开始检查
        AVLNode current = insertPos;
        while (true)
        {
            // 如果节点的平衡因子为0,不需要再回朔了,直接返回
            if (current.bf == 0)
            {
                return;
            }
            // 如果节点的平衡因子为1或者-1,首先修正父节点的平衡因子,但是要先判断当前节点是否是root
            else if (current.bf == 1 || current.bf == -1)
            {
                // 如果已经回朔到根节点,则直接返回
                if (current == root)
                {
                    return;
                }
                // 如果插入的节点在当前节点的父节点的左边,则将父节点的bf值+1
                else if (data < current.parent.data)
                {
                    current.parent.bf += 1;
                }
                // 否则当前节点的父节点的bf值减一
                else
                {
                    current.parent.bf -= 1;
                }
                // 继续回朔当前的父节点
                current = current.parent;
            }
            // 如果节点的平衡因子的绝对值大于1,则说明找到了最小不平衡子树的根,下面左旋转修正操作
            else if (current.bf == 2 || current.bf == -2)
            {
                // 比较一下data数据的大小即可知道插入的是左边还是右边了。。。
                // /首先确定是什么类型的旋转RR,LL,RL,LR
                // LL型,插在当前节点的左子树的左子树,因为data小于当前节点的data,
                // 所以当前节点的左子树必不为空,即有两个节点位置需要调整,current、current.left
                // A-current
                // /
                // B-current.left
                // /
                // C 需要将current绕着B节点右旋,bf值改变的节点为A和B
                if (data < current.data && data < current.left.data)
                {
                    // 这里需要分两种情况,一种是当前节点为根节点,一种是非根节点
                    // 还要再分两种情况,一种是current.left有右节点,一种是current.left没有右节点
                    // 这里有个疑问,如何在调整完节点位置之后修正节点的bf值
                    // 如果当前节点为根节点,即父节点为null
                    rightRotate(current);
                }
                // RR类型旋转
                else if (data >= current.data && data >= current.right.data)
                {
                    
                    leftRotate(current);
                }
                // LR型旋转,先要将current.left绕着current.left.right左旋,再将current绕着current.left右旋
                else if (data < current.data && data >= current.left.data)
                {
                    leftRotate(current.left);
                    rightRotate(current);
                }
                else
                {
                    rightRotate(current.right);
                    leftRotate(current);
                }
                // 如果B的bf值为0或者B为根节点,则跳出循环
                if (current.parent == root || current.parent.bf == 0)
                {
                    break;
                }
                // 否则继续检查B的父节点
                else
                {
                    current = current.parent.parent;
                }
            }
        }
    }
    
    /**
     * AVL树删除操作,首先找到删除的节点,如果左子树不为空,则将待删除节点的数据和左子树中data最大的节点的数据交换,否则如果右子树不为空,
     * 则将待删除节点与右子树中最小的节点交换数据,实际删除的都是叶子节点,然后回朔修改bf值
     * 
     * @return
     */
    public AVLNode delete(int data)
    {
        AVLNode current = root;
        while (current != null)
        {
            if (data < current.data)
            {
                current = current.left;
            }
            else if (data > current.data)
            {
                current = current.right;
            }
            else
            {// 找到该节点了,下面是找到实际的叶子节点与该节点交换
                // 如果该节点的左子树不为空,则将左子树的最大节点与该节点交换
                int temp = current.data;
                AVLNode tempNode = null;
                if (current.left != null)
                {
                    tempNode = maxNode(current.left);
                }
                else if (current.right != null)
                {
                    tempNode = minNode(current.right);
                }
                if (tempNode != null)
                {
                    current.data = tempNode.data;
                    tempNode.data = temp;
                    current = tempNode;
                }
                // 下面是具体的删除操作了,其实就是删除叶子节点了
                if (current == root)
                {
                    root = null;
                    return current;
                }
                else if (current == current.parent.left)
                {// 如果当前节点是其父节点的左子树
                    if (current.left != null)
                    {// 如果当前节点的左子树不为空
                        current.parent.left = current.left;
                        current.left.parent = current.parent;
                    }
                    else if (current.right != null)
                    {
                        current.parent.left = current.right;
                        current.right.parent = current.parent;
                    }
                    else
                    {
                        current.parent.left = null;
                    }
                    current.parent.bf -= 1;
                }
                else
                {// 如果当前节点是其父节点的右子树
                    if (current.left != null)
                    {// 如果当前节点的左子树不为空,则将当前节点的左子树链接到当前节点的父节点
                        current.parent.right = current.left;
                        current.left.parent = current.parent;
                    }
                    else if (current.right != null)
                    {
                        current.parent.right = current.right;
                        current.right.parent = current.parent;
                    }
                    else
                    {
                        current.parent.right = null;
                    }
                    current.parent.bf += 1;
                }
                tempNode = current.parent;// 这里用上面的tempNode节点作为回朔的开端,省的定义太多变量很乱
                // 下面是删除操作的回朔算法
                while (true)
                {
                    // 如果节点的bf为1或者-1,说明删除之前的bf为0(因为删除之前是平衡的,不可能为2或者-2情况),删除之后树的高度没有改变,不需要再回朔判断
                    if (tempNode.bf == 1 || tempNode.bf == -1)
                    {
                        return current;
                    }
                    else if (tempNode.bf == 0)
                    {// 如果节点的bf为0,说明删除之前bf为1或者-1,删除之后高度减少了,那么需要首先判断当前节点是父节点的左子树还是右子树,再回朔父节点
                        // 首先需要判断是否已经回朔到了根节点
                        if (tempNode == root)
                        {
                            return current;
                        }
                        else if (tempNode == tempNode.parent.left)
                        {// 如果当前节点是父节点的左子树,说明父节点的左子树高度下降了
                            tempNode.parent.bf -= 1;
                        }
                        else
                        {
                            tempNode.parent.bf += 1;
                        }
                    }
                    else
                    {// 如果节点的bf为2或者-2,则需要通过旋转保持平衡,首先确定旋转的类型,bf值大于等于0向左,小于0向右
                        if (tempNode.bf >= 0 && tempNode.left.bf >= 0)
                        {// LL型旋转
                            rightRotate(tempNode);
                        }
                        else if (tempNode.bf >= 0 && tempNode.left.bf < 0)
                        {// LR型旋转
                            leftRotate(tempNode.left);
                            rightRotate(tempNode);
                        }
                        else if (tempNode.bf < 0 && tempNode.right.bf >= 0)
                        {// RL型旋转
                            rightRotate(tempNode.right);
                            leftRotate(tempNode);
                        }
                        else
                        {// RR型旋转
                            leftRotate(tempNode);
                        }
                    }
                    tempNode = tempNode.parent;
                }
            }
        }
        return current;
    }
    
    /**
     * 返回一个树的最大值节点
     * 
     * @param root
     * @return
     */
    private AVLNode maxNode(AVLNode root)
    {
        AVLNode current = root;
        while (current != null)
        {
            if (current.right == null)
            {
                break;
            }
            else
            {
                current = current.right;
            }
        }
        return current;
    }
    
    /**
     * 返回一个树的最小值节点
     * 
     * @param root
     * @return
     */
    private AVLNode minNode(AVLNode root)
    {
        AVLNode current = root;
        while (current != null)
        {
            if (current.left == null)
            {
                break;
            }
            else
            {
                current = current.left;
            }
        }
        return current;
    }
    
    /**
     * 将节点左旋的方法
     * 
     * @param node
     * @see [类、类#方法、类#成员]
     */
    private void leftRotate(AVLNode node)
    {
        // 旋转代码
        if (node.parent == null)
        {
            root = node.right;
        }
        else if (node == node.parent.left)
        {
            node.parent.left = node.right;
        }
        else
        {
            node.parent.right = node.right;
        }
        node.right.parent = node.parent;
        if (node.right.left != null)
        {
            node.right.left.parent = node;
        }
        node.parent = node.right;
        node.right = node.parent.left;
        node.parent.left = node;
        // 调整平衡因子
        if (node.parent.bf < 0)//如果父节点的平衡因子小于0
        {
            node.bf = node.bf - node.parent.bf + 1;
        }
        else
        //如果父节点的平衡因子大于或等于0
        {
            node.bf += 1;
        }
        if (node.bf < 0)
        {
            node.parent.bf += 1;
        }
        else
        {
            node.parent.bf = node.parent.bf + node.bf + 1;
        }
    }
    
    /**
     * 将节点右旋的方法
     * 
     * @param node
     * @see [类、类#方法、类#成员]
     */
    private void rightRotate(AVLNode node)
    {
        if (node.parent == null)
        {
            root = node.left;
        }
        else if (node == node.parent.left)
        {
            node.parent.left = node.left;
        }
        else
        {
            node.parent.right = node.left;
        }
        // 将B的父节点设为A的父节点
        node.left.parent = node.parent;
        // 如果B的右子树不为null,则将B的右子树的父节点设为A
        if (node.left.right != null)
        {
            node.left.right.parent = node;
        }
        // 将A的父节点设为B
        node.parent = node.left;
        // 将B的右子树接到A的左边
        node.left = node.parent.right;
        node.parent.right = node;
        // 求得当前节点旋转后的bf值,这个是经过公式推导出来的会有三种情况-1,0,1
        //        node.bf = node.bf - node.parent.bf - 1;
        //        if (node.bf == -1)
        //        {
        //            node.parent.bf -= 2;
        //        }
        //        else
        //        {
        //            node.parent.bf -= 1;
        //        }
        if (node.parent.bf >= 0)
        {
            node.bf = node.bf - node.parent.bf - 1;
        }
        else
        {
            node.bf -= 1;
        }
        if (node.bf >= 0)
        {
            node.parent.bf -= 1;
        }
        else
        {
            node.parent.bf = node.parent.bf + node.bf - 1;
        }
    }
    
    /**
     * 中序遍历二叉树
     * 
     * @see [类、类#方法、类#成员]
     */
    public void middleDisplay()
    {
        middleDisplay(root);
    }
    
    /**
     * 使用递归方式中序遍历二叉树
     * 
     * @param root
     * @see [类、类#方法、类#成员]
     */
    private void middleDisplay(AVLNode root)
    {
        if (root != null)
        {
            middleDisplay(root.left);
            root.displayNode();
            middleDisplay(root.right);
        }
    }
}
    原文作者:AVL树
    原文地址: https://blog.csdn.net/dc15822445347/article/details/8244506
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞