(八)二叉树—平衡二叉树

1、基本介绍

左旋转

右旋转

双旋转

2、应用实例

package tree;

/*
    左旋转:
        //  1、创建一个新节点,值为当前根节点的值
        //  2、把根节点的左子树 设置 为新节点的左子树
        //  3、把根节点的右子树的左子树 设置 为新节点的右子树
        //  4、把根节点的值替换为其右子节点的值
        //  5、把根节点的右子树 设置为 右子树的右子树
        //  6、把根节点的左子树 设置为 新节点

    右旋转:
        //  1、创建一个新节点,值为当前根节点的值
        //  2、把根节点的右子树 设置 为新节点的右子树
        //  3、把根节点的左子树的右子树 设置 为新节点的左子树
        //  4、把根节点的值替换为其左子节点的值
        //  5、把根节点的左子树 设置为 左子树的左子树
        //  6、把根节点的右子树 设置为 新节点
 */
public class AVLTreeDemo {
    public static void main(String[] args) {
        AVLTree tree1 = createAVLTree(new int[]{4,3,6,5,7,8});   // 测试左旋转
        AVLTree tree2 = createAVLTree(new int[]{10,12,8,9,7,6}); // 测试右旋转
        AVLTree tree3 = createAVLTree(new int[]{10,11,7,6,8,9}); // 测试双旋转

        System.out.print("中序遍历:");
        tree1.inOrderTraverse();
        System.out.print("中序遍历:");
        tree2.inOrderTraverse();
        System.out.print("中序遍历:");
        tree3.inOrderTraverse();

        //  获取根节点所在的经左旋转后二叉排序树的高度、左子树高度以及右子树高度
        System.out.println("\n当前根节点:" + tree1.root);
        System.out.println("树的高度:" + tree1.root.height());
        System.out.println("左子树的高度:" + tree1.root.leftHeight());
        System.out.println("右子树的高度:" + tree1.root.rightHeight());
        System.out.println();


        //  获取根节点所在的经左旋转后二叉排序树的高度、左子树高度以及右子树高度
        System.out.println("当前根节点:" + tree2.root);
        System.out.println("树的高度:" + tree2.root.height());
        System.out.println("左子树的高度:" + tree2.root.leftHeight());
        System.out.println("右子树的高度:" + tree2.root.rightHeight());
        System.out.println();


        //  获取根节点所在的经左旋转后二叉排序树的高度、左子树高度以及右子树高度
        System.out.println("当前根节点:" + tree3.root);
        System.out.println("树的高度:" + tree3.root.height());
        System.out.println("左子树的高度:" + tree3.root.leftHeight());
        System.out.println("右子树的高度:" + tree3.root.rightHeight());
        System.out.println();

    }

    public static AVLTree createAVLTree(int[] arr) {
        AVLTree tree = new AVLTree();
        for (int temp : arr) {
            tree.add(new ANode(temp));
        }
        return tree;
    }
}

class AVLTree {
    public ANode root;

    //  添加节点
    public void add(ANode node) {
        if (this.root == null) { // 判断当前是否是空树,是的话直接赋给root
            this.root = node;
        } else {
            this.root.add(node);
        }
    }

    //  中序遍历
    public void inOrderTraverse() {
        if (this.root != null) {
            this.root.inOrderTraverse();
            System.out.println();
        }
    }


//-----------------------------------------------------
    //  删除节点
    public void delANode(int data) {
        if (this.root == null) {
            return;
        } else {
            this.root.delANode(data);
        }
    }

    //  查找待删节点
    public ANode searchDelANode(int data) {
        if (this.root == null) {
            return null;
        } else {
            return this.root.searchDelANode(data);
        }
    }

    //  查找待删节点的父结点
    public ANode searchParentANode(int data) {
        if (this.root == null) {
            return null;
        } else {
            return this.root.searchParentANode(data);
        }
    }

    public int searchRightMin(ANode ANode) {
        if (this.root == null) {
            return -1;
        } else {
            return this.root.searchRightMin(ANode);
        }
    }

    public int searchLeftMax(ANode ANode) {
        if (this.root == null) {
            return -1;
        } else {
            return this.root.searchLeftMax(ANode);
        }
    }
}

class ANode {
    public int data;
    public ANode left;
    public ANode right;
    public ANode(int data) {
        this.data = data;
        this.left = null;
        this.right = null;
    }

    //  添加节点
    public void add(ANode node) {
        if (node == null) {
            return;
        }
        //  先判断大小,决定是放左子树还是右子树
        if (node.data > this.data) {
            //  要放右边的话,判断其右子树是否为空
            if (this.right == null) {
                this.right = node;
            } else {
                this.right.add(node);
            }
            //  要放左边的话,判断其左子树是否为空
        } else {
            if (this.left == null) {
                this.left = node;
            } else {
                this.left.add(node);
            }
        }

        //  在添加节点时,当左、右子树高度差大于1时,就要进行左右旋转

        /*
            如果右子树高度 - 左子树高度 > 1,则需要进行左旋转
            注意:当符合左旋转条件时:
                        如果根节点的右子树下的左子树高度 大于 右子树高度,
                        就先要对该右子节点所在的右子树进行右旋转,再对根节点进行左旋转
                不符合的话,可以直接进行左旋转
         */
        if (rightHeight() - leftHeight() > 1) {
            if (this.right != null && this.right.leftHeight() > this.right.rightHeight()) {
                this.right.rightRotate();
                leftRotate();
            } else {
                leftRotate();
            }
            return;     //  旋转后就中止下面的旋转
        }


        /*
            如果左子树高度 - 右子树高度 > 1,则需要进行右旋转
            注意:当符合右旋转条件时:
                    如果根节点的左子树下的右子树高度 大于 左子树高度,
                    就先要对该左子节点所在的左子树进行左旋转,再对根节点进行右旋转
                 不符合的话,可以直接进行右旋转
         */
        if (leftHeight()  - rightHeight() > 1) {
            if (this.left != null && this.left.rightHeight() > this.left.leftHeight()) {
                this.left.leftRotate();
                rightRotate();
            } else {
                rightRotate();
            }
        }
    }

    //  中序遍历
    public void inOrderTraverse() {
        if (this.left != null) {
            this.left.inOrderTraverse();
        }
        System.out.print(this.data + " ");
        if (this.right != null) {
            this.right.inOrderTraverse();;
        }
    }

    //  左旋转
    public void leftRotate() {
        //  1、创建一个新节点,值为当前根节点的值
        ANode newNode = new ANode(this.data);
        //  2、把根节点的左子树 设置 为新节点的左子树
        newNode.left = this.left;
        //  3、把根节点的右子树的左子树 设置 为新节点的右子树
        newNode.right = this.right.left;
        //  4、把根节点的值替换为其右子节点的值
        this.data = this.right.data;
        //  5、把根节点的右子树 设置为 右子树的右子树
        this.right = this.right.right;
        //  6、把根节点的左子树 设置为 新节点
        this.left = newNode;
    }

    //  右旋转
    public void rightRotate() {
        //  1、创建一个新节点,值为当前根节点的值
        ANode newNode = new ANode(this.data);
        //  2、把根节点的右子树 设置 为新节点的右子树
        newNode.right = this.right;
        //  3、把根节点的左子树的右子树 设置 为新节点的左子树
        newNode.left =  this.left.right;
        //  4、把根节点的值替换为其左子节点的值
        this.data = this.left.data;
        //  5、把根节点的左子树 设置为 左子树的左子树
        this.left = this.left.left;
        //  6、把根节点的右子树 设置为 新节点
        this.right = newNode;
    }


    //  获取左子树的高度
    public int leftHeight() {
        if (this.left == null) {
            return 0;
        } else {
            return this.left.height(); // 方法不要调错了,左子树它也是树
        }
    }

    //  获取右子子树的高度
    public int rightHeight() {
        if (this.right == null) {
            return 0;
        } else {
            return this.right.height();// 方法不要调错了,右子树它也是树
        }
    }

    //  获取树的高度
    public int height() {
        //  取左、右子树高度最大值 + 1(根节点那一层)
        return (Math.max(this.left == null ? 0 : this.left.height(),
                this.right == null ? 0 : this.right.height()) + 1);
    }

//-----------------------------------------------------

    public void delANode(int data) {
        ANode targetANode = searchDelANode(data);
        ANode parentANode = searchParentANode(data);
        if (targetANode == null || parentANode == null) {
            return;
        }
        //   第一种情况:删除的是叶子节点
        if (targetANode.left == null && targetANode.right == null) {
            //  判断删除节点是父节点的左子节点还是右子结点,从而对应删除
            if (parentANode.left == targetANode)  {
                parentANode.left = null;
            } else if (parentANode.right == targetANode) {
                parentANode.right = null;
            }

            //   第二种情况:删除的是只有一棵子树的非叶子节点
        } else if ((targetANode.left == null && targetANode.right != null) ||
                (targetANode.left != null && targetANode.right == null)) {
            //  先判断删除节点有左子树还是右子树
            // 有左子树
            if (targetANode.left != null) {
                //  再判断它是父节点的左子节点还是右子节点
                if (targetANode == parentANode.left) {
                    parentANode.left = targetANode.left;
                } else if (targetANode == parentANode.right) {
                    parentANode.right = targetANode.left;
                }
                //  右子树
            } else if (targetANode.right != null) {
                //  再判断它是父节点的左子节点还是右子节点
                if (targetANode == parentANode.left) {
                    parentANode.left = targetANode.right;
                } else if (targetANode == parentANode.right){
                    parentANode.right = targetANode.right;
                }
            }

            //   第三种情况:删除的是有两棵子树的非叶子节点
        } else if (targetANode.left != null && targetANode.right != null) {
            //  无需判断删除节点是父节点的左子树还是右子树
            //  只需找到删除节点的右子树的最小节点 或者 找到删除节点的左子树的最大节点
//            int temp = searchRightMin(targetANode.right);
            int temp  = searchLeftMax(targetANode.left);
            targetANode.data = temp;
        }
    }

    public ANode searchDelANode(int data) {
        if (this.data == data) {
            return this;
        } else if (data <= this.data) {
            if (this.left != null) {
                return this.left.searchDelANode(data);
            }
        } else {
            if (this.right != null) {
                return this.right.searchDelANode(data);
            }
        }
        return null;
    }

    public ANode searchParentANode(int data) {
        if ((this.left != null && this.left.data == data) ||
                (this.right != null && this.right.data == data)) {
            return this;
        } else {
            if (this.left != null && data < this.data) {
                return this.left.searchParentANode(data);
            }else if (this.right != null && data > this.data) {
                return this.right.searchParentANode(data);
            } else {
                return null;
            }
        }
    }

    public int searchRightMin(ANode ANode) {
        //  找该节点所在子树的最小值(根据二叉排序树特点,一般在最左边)
        ANode temp = ANode;
        while (temp.left != null) {
            temp = temp.left;
        }
        delANode(temp.data);  // 删除该最小子结点
        return temp.data;
    }

    public int searchLeftMax(ANode ANode) {
        //  找该节点所在子树的最大值(根据二叉排序树特点,一般在最右边)
        ANode temp = ANode;
        while (temp.right != null) {
            temp = temp.right;
        }
        delANode(temp.data);  // 删除该最小子结点
        return temp.data;
    }

    @Override
    public String toString() {
        return "ANode[data=" + this.data + "]";
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来得晚一些也行

观众老爷,请赏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值