平衡二叉树

声明:下面的代码只是一个最基础的实现,没有经过严格的测试

/**
 * 平衡二叉树(AVL)
 * 1,可以保证查询效率,它是一棵空树或者它的左右两个子树的高度差不超过1,并且左右两个子树都是一颗平衡二叉树。
 * 2,实现方式有:红黑树,AVL算法,替罪羊树,Treap,伸展树等。
 * 3,平衡二叉树是一种特殊的二叉排序树。除了满足二叉排序树的特性之外,必须在添加新节点时,通过判断左右子树的高度
 * 通过左旋转或者右旋转来满足平衡二叉树的特性,即左右两个子树的高度差不能超过1
 */
public class BinaryAVLTree {
        public Node root;

        public static void main(String[] args) {
            BinaryAVLTree tree = new BinaryAVLTree();
            int[] arr={10,11,7,6,8,9};
            for (int i : arr) {
                tree.addNode(i);
            }
/*            tree.deleteNode(5);
            tree.infixOrder();*/
            // System.out.println(tree.height(tree.root));  3
           // System.out.println(tree.height(tree.root.left));  2
            // System.out.println(tree.height(tree.root.right)); 2
            //System.out.println(tree.root);  8
        }

        public void addNode(int value){
            if(root == null){
                root = new Node(value);
            }else {
                addNode(root,value);
            }
        }


        //递归计算树的高度,每一个节点的高度等于它的子节点高度(左子节点和右子节点取最高的那个) + 1
        public int height(Node node){
            if(node== null ){
                return 0;
            }else{
                int rightHeight=height(node.right);
                int leftHeight=height(node.left);
                return Math.max(leftHeight,rightHeight)+1;
            }

        }
        public int rightHeight(Node node){
            if(node.right == null){
                return 0;
            }
            return height(node.right);
        }

        public int leftHeight(Node node){
            if(node.left == null){
                return 0;
            }
            return height(node.left);
        }

        // 对于二叉排序树,中序遍历时输出的值 是 升序排列的
        public void infixOrder(){
            if(root != null){
                infixOrder(root);
            }else{
                System.out.println("该二叉树为空");
            }
        }


        //中序遍历,先左节点再父节点,后右节点
        private void infixOrder(Node node){
            if(node==null){
                return;
            }

            //每次都是先输出父节点
            if(node.left!=null){
                infixOrder(node.left);
            }
            System.out.println(node);
            if(node.right!=null){
                infixOrder(node.right);
            }
        }

        /**
         * 使用递归的方式新增元素:按照二叉排序树的定义,如果待插入的值比父节点小,则作为左节点。反之则为右节点。
         * 值插入的逻辑:先从根节点开始,插入的值和根节点的值比较大小,放到合适的位置。如果根节点有左节点或右节点,那么根节点
         * 的左节点或者有节点作为新的父节点,继续和待插入的值比较。直至父节点为null。
         * @param parentNode  待插入节点的父节点
         * @param value 待插入的值
         */
        private void addNode(Node parentNode,int value){
            if(parentNode == null){
                return;
            }
            if(value < parentNode.value ){
                if(parentNode.left == null){
                    parentNode.left=new Node(value);
                }else{
                    //如果父节点存在左节点,那么该左节点作为新的父节点进行递归
                    addNode(parentNode.left,value);
                }
            }

            if(value >= parentNode.value){
                if(parentNode.right == null){
                    parentNode.right=new Node(value);
                }else{
                    //如果父节点存在右节点,那么该右节点作为新的父节点进行递归
                    addNode(parentNode.right,value);
                }
            }
            Node curNode=parentNode;

            //添加完一个节点后,如果右子树高度比左子树高度 大于1
            if(rightHeight(curNode) - leftHeight(curNode) > 1){
                //如果右子树的左高度大于右子树的右高度
                if(curNode.right != null && leftHeight(curNode.right) > rightHeight(curNode.right)){
                    //先对当前节点的右子树进行右旋转
                    rightHeight(curNode.right);
                    //再对当前节点进行左旋转
                    leftHeight(curNode);

                }else{
                    //直接对当前节点进行左旋转即可
                    leftHeight(curNode);
                }

            }

            //添加完一个节点后,如果左子树高度比右子树高度 大于1
            if(leftHeight(curNode) - rightHeight(curNode) > 1){
                //如果左子树的右高度大于左子树的左高度
                if(curNode.left != null && rightHeight(curNode.left) > leftHeight(curNode.left)){
                    //先对当前节点的左子树进行左旋转
                    leftRotate(curNode.left);
                    //再对当前节点进行右旋转
                    rightRotate(curNode);

                }else{
                    //直接对当前节点进行右旋转即可
                    rightRotate(curNode);
                }

            }


        }

        //左旋转。如果左树比右树高,则进行左旋转
        private void leftRotate(Node node){
            //1,以当前节点的值创建一个新节点
            Node newNode = new Node(node.value);
            //2,新节点的左子树设置为当前节点的左子树
            newNode.left=node.left;
            //3,新节点的右子树设置为当前节点右子树的左子树
            newNode.right=node.right.left;
            //4,当前节点的值替换为右子节点的值
            node.value=node.right.value;
            //5,当前节点的右子树设置为当前节点右子树的右子树
            node.right=node.right.right;
            //6,当前节点的左子树(左节点)设置为新节点
            node.left=newNode;

        }


    //右旋转。如果右树比左树高,则进行右旋转
    private void rightRotate(Node node){
        //1,以当前节点的值创建一个新节点
        Node newNode = new Node(node.value);
        //2,新节点的右子树设置为当前节点的右子树
        newNode.right=node.right;
        //3,新节点的左子树设置为当前节点左子树的右子树
        newNode.left=node.left.right;
        //4,当前节点的值替换为左子节点的值
        node.value=node.left.value;
        //5,当前节点的左子树设置为当前节点左子树的左子树
        node.left=node.left.left;
        //6,当前节点的右子树(右节点)设置为新节点
        node.right=newNode;

    }


        class Node{
            //value
            private Integer value;
            //左节点
            public Node left;
            //右节点
            public Node right;

            public Node(Integer value) {
                this.value = value;
            }

            @Override
            public String toString() {
                return "Node{" +
                        "value=" + value +
                        '}';
            }
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值