平衡二叉树 AVL树(java)

平衡二叉树(AVL树)

创建二叉排序树{1,2,3,4,5}时,左子树全部为空,查询速度明显降低,无法发挥二叉排序树的优势,所以需要平衡二叉树

平衡二叉树它的左右两个子树的高度差绝对值不超过1,并且它的左右两个子树也都是平衡二叉树。

当需要创建一颗AVL树的时候,往往需要__左旋转,右旋转,双旋转__

旋转方法添加在Node类中的add方法中

  • 左旋转

    当数列{4,3,6,5,7}加入8时,rightHight()-leftHight() > 1成立, 树就不是一个AVL树了在这里插入图片描述

  • 思路:

    1. 创建一个新的节点,值等于当前节点的值
    2. 将新节点的左子树设置为当前节点的左子树
    3. 将新节点的右子树设置为当前节点的右子树的左子树
    4. 把当前节点的值设置为右子节点的值
    5. 把当前节点的右子树设置为右子树的右子树
    6. 把当前节点的左节点设置为新节点
  • 右旋转

    思路和左旋转相同。

  • 双旋转

    有时不能实现一次单旋转完成二叉树的转换,需要双旋转。

    当需要进行右旋转时,如果它的左子树的右子树高度大于左子树的左子树高度时,先对这个节点的左节点进行左旋转,在对当前节点进行右旋转。


代码实现:

package com.tree.AVL;

public class AVL_Tree {
    public static void main(String[] args) {
        AVLTree avlTree = new AVLTree();
//        int[] arr = {4,3,6,5,7,8};
        int[] arr = {10,11,7,6,8,9};
        for (int i = 0; i < arr.length; i++) {
            avlTree.add(new Node_(arr[i]));
        }
        System.out.println("树高度:");
        System.out.println(avlTree.root.hight());

        System.out.println("左右子树高度:");
        System.out.println(avlTree.root.leftHight());
        System.out.println(avlTree.root.rightHight());

        //
    }

}
    //创建树
class AVLTree {
        Node_ root;

        public void add(Node_ node) {
            if (root == null) {
                root = node;
            } else {
                root.add(node);
            }
        }

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

        //调用search方法
        public Node_ search(int value) {
            if (root == null) {
                return null;
            } else {
                return root.search(value);
            }
        }

        //调用searchParent
        public Node_ searchParent(int value) {
            if (root == null) {
                return null;
            } else {
                return root.searchParent(value);
            }
        }

        //寻找并删除最小子节点,返回最小子节点的值
        public int delMin(Node_ node) {
            Node_ target = node;
            while (target.left != null) {
                target = target.left;
            }
            del(target.value);
            return target.value;
        }

        //删除节点
        public void del(int value) {
            Node_ targetNode = search(value);
            if (targetNode == null) {
                return;
            }
            if (root.left == null && root.right == null) {
                root = null;
                return;
            }

            Node_ targetNodeParent = searchParent(value);

            //判断 1. 如果删除的是叶子节点——判断这个节点是左子节点还是右子节点,删除
            if (targetNode.left == null && targetNode.right == null) {
                if (targetNodeParent.left != null && targetNodeParent.left.value == value) {
                    targetNodeParent.left = null;
                } else {
                    targetNodeParent.right = null;
                }
            } else if (targetNode.left != null && targetNode.right != null) {
                //判断 2. 如果删除的是有两颗子树的节点——找到要删除节点的右子树的最小子节点,并使targetNode = 删去节点的值
                int min = delMin(targetNode.right);
                targetNode.value = min;
            } else {
                //判断 3. 如果删除只有一颗子树的节点——判断targetnodeParent的左子节点是targetNode还是右子节点是targetNode
                if (targetNodeParent.left.value == targetNode.value) {
                    //目标节点是其父节点的左子节点
                    if (targetNode.left != null) {
                        targetNodeParent.left = targetNode.left;
                    } else {
                        targetNodeParent.left = targetNode.right;
                    }
                } else {
                    //目标节点是其父节点的右子节点
                    if (targetNode.right != null) {
                        targetNodeParent.right = targetNode.right;
                    } else {
                        targetNodeParent.right = targetNode.left;
                    }
                }
            }
        }
    }

    //创建节点
class Node_ {
        int value;
        Node_ left;
        Node_ right;

        public Node_(int value) {
            this.value = value;
        }

        public void add(Node_ node) {
            if (node.value < this.value) {
                if (this.left == null) {
                    this.left = node;
                } else {
                    this.left.add(node);
                }
            } else {
                if (this.right == null) {
                    this.right = node;
                } else {
                    this.right.add(node);
                }
            }
            //判断是否满足AVLtree
            if(this.rightHight()-this.leftHight()>1){
                if(right.leftHight()>right.rightHight()){
                    left.rightRotate();
                }
                leftRotate();
            }
            if(this.leftHight()-this.rightHight()>1){
                if(left.rightHight()>left.leftHight()){
                    left.leftRotate();
                }
                rightRotate();
            }
        }

        //计算以当前节点为根节点的树的高度
        public int hight(){
            return Math.max(left == null?0:left.hight(),right == null?0:right.hight())+1;
        }

        //左子树的高度
        public int leftHight(){
            if(left == null){
                return 0;
            }
            return left.hight();
        }

        //右子树的高度
        public int rightHight(){
            if(right == null){
                return 0;
            }
            return right.hight();
        }

        //找到要删去的节点
        public Node_ search(int value) {
            if (this.value == value) {
                return this;
            } else if (value < this.value) {
                if (this.left == null) {
                    return null;
                }
                return this.left.search(value);
            } else {
                if (this.right == null) {
                    return null;
                }
                return this.right.search(value);
            }
        }

        //找到要删除节点的父节点
        public Node_ searchParent(int value) {
            if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) {
                return this;
            } else {
                if (value < this.value && this.left != null) {
                    return this.left.searchParent(value);
                } else if (value > this.value && this.right != null) {
                    return this.right.searchParent(value);
                } else {
                    return null;
                }
            }
        }


        //中序遍历
        public void middleOrder() {
            if (this.left != null) {
                this.left.middleOrder();
            }
            System.out.println(this.value);
            if (this.right != null) {
                this.right.middleOrder();
            }
        }

        //左旋转
        public void leftRotate(){
            Node_ newNode = new Node_(value);
            newNode.left = left;
            newNode.right = right.left;
            value = right.value;
            right = right.right;
            left = newNode;
        }

        //右旋转
        public void rightRotate(){
            Node_ newNode = new Node_(value);
            newNode.right = right;
            newNode.left = left.right;
            value = left.value;
            left = left.left;
            right = newNode;
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值