平衡二叉树

简介

虽然搜索二叉树在查询,删除,添加上具有一定的优势,但是在一些情况下的效率也特别低。比如下面的这个搜索二叉树:
在这里插入图片描述
对于这样的搜索二叉树,我们进行添加,查找,删除时依然很麻烦。因此,我们需要将这样的搜索二叉树转为平衡二叉树。

平衡二叉树(AVL)的定义

首先,平衡二叉树是搜索二叉树。其次,平衡二叉树的左子树和右子树高度的绝对值不超过1.

平衡二叉树的单旋转

对于左左结构的二叉树:
在这里插入图片描述
对图3进行右旋步骤的详解:
在这里插入图片描述
对节点8进行旋转
第一步:创建一个和当前节点值一样的节点。
在这里插入图片描述
第二步:把当前节点的右节点赋值给新节点的右节点。
在这里插入图片描述
第三步:如果当前节点的左节点的右节点不为空,则把它赋值给新节点的左节点。
在这里插入图片描述
第四步:将当前节点的左节点的值赋给当前节点。
在这里插入图片描述
第五步:删除当前节点的左节点,即把当前节点的左节点的左节点赋值给当前节点的左节点。
在这里插入图片描述
第六步:将新节点赋值给当前节点的右节点
在这里插入图片描述

对于右右结构的二叉树,我们采用左旋,方法与右旋类似。

双旋转

对于下面结构的二叉树,我们通过单旋转无法将它转为平衡二叉树,因此我们就需要双旋转即两次旋转
在这里插入图片描述
对于这样的二叉树转为平衡二叉树,我们需要分两步进行。
第一步:对节点5进行左旋
在这里插入图片描述
第二步:对节点8进行右旋
在这里插入图片描述

代码

Node类

package com.wuxudong.AVLTree;

public 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);
            }

        }
        //在添加完节点后判断是不是平衡二叉树

        //如果左节点的高度减去有节点的高度大于等于2需要进行右旋转
        if (leftHeight()-rightHeight()>=2){

            if (left!=null&&left.leftHeight()<left.rightHeight()){
                //左节点先左旋转
                left.leftRotate();
                //当前节点右旋
                rightRotate();

            }else {
                //右旋转
                rightRotate();
            }
        }
        if (leftHeight()-rightHeight()<=-2){

            if (right!=null&&right.rightHeight()<right.leftHeight()){
                right.rightRotate();
                leftRotate();
            }else {
                //左旋转
                leftRotate();
            }
        }

    }

    private void leftRotate() {

        Node newNode=new Node(this.value);

        newNode.left=left;
        if (right.left!=null) {
            newNode.right = right.left;
        }


        this.value=right.value;

        this.right=this.right.right;

        this.left =newNode;
    }

    private void rightRotate() {
        //创建一个和当前节点值一样的新节点
        Node newNode=new Node(this.value);
        //将当前的右节点赋值给新节点的右节点
        newNode.right=right;
        //将当前节点的左节点的右节点赋值给新节点的左节点
        if (left.right!=null) {
            newNode.left = left.right;
        }
        //将当前节点的左节点的值赋值给当前节点
        this.value=left.value;
        //将当前左节点的左节点赋值给当前节点的左节点
        this.left=this.left.left;
        //将新节点作为当前节点的右节点
        this.right=newNode;
    }

    //获取左节点的高度
    public int leftHeight(){
        if (left==null){
            return 0;
        }
        return left.height();
    }

    //获取右节点的高度
    public int rightHeight(){
        if (right==null){
            return 0;
        }
        return right.height();
    }

    //获取节点的高度
    public int height() {

        return Math.max(this.left==null?1:this.left.height()+1,this.right==null?1:this.right.height()+1);
    }




    public void midShow(Node node){
        if (node==null){
            return;
        }
        midShow(node.left);
        System.out.println(node.value);
        midShow(node.right);


    }


    public void midShow() {
        Node root=this;
        midShow(root);
    }

    public Node search(int value) {
        //获取当前节点
        Node node=this;
        if (this.value==value){
            return node;
        }else if (this.value<value){

            return node.right.search(value);
        }else {

           return node.left.search(value);
        }

    }

    public Node findParent(Node node) {
        if ((this.left!=null&&this.left.value==node.value)||(this.right!=null&&this.right.value==node.value)){
            return this;
        }else if (this.value>node.value){
            return this.left.findParent(node);
        }else if (this.value<node.value){
            return this.right.findParent(node);
        }else {
            return null;
        }


    }

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

AVLTree类

package com.wuxudong.AVLTree;

public class AVLTree {

    Node root;

   //添加节点
   public void add(Node node){
       if (root==null){
           root=node;
       }else {
           root.add(node);
       }
   }

    //中序遍历,即按照已经排好的顺序
    public void midShow(){
        root.midShow();
    }

    //查找节点
    public Node search(int value){
       if (root==null){
           return null;
       }else {
           return root.search(value);
       }


    }


    public void deleteNode(int i) {
       if (root==null){
           return;
       }else {
           //找出要删除的节点
           Node node=search(i);
           //如果找不到这个节点
           if (node==null){
               return;
           }
           //找出删除节点的父节点
           Node parent = findParent(node);

           //如果删除的节点是叶子节点
           if (node.left==null&&node.right==null&&parent.left==node){
                parent.left=null;
           }else if (node.right==null&&node.left==null&&parent.right==node){
               parent.right=null;
               //如果删除的节点只有一个子节点
                //右节点为空
           }else if (node.right==null&&node.left!=null){
               parent.left=node.left;
               //左节点为空
           }else if (node.left==null&&node.right!=null){
               parent.right=node.right;
           }else {
               //删除的节点有两个节点
               //找出右子树的最小值
               int min=findRightMin(node.right);
               node.value=min;


           }
       }
    }

    public int findRightMin(Node node) {
       Node target=node;
       while (target.left!=null){
           target=target.left;
       }
       deleteNode(target.value);
       return target.value;


    }

    public Node findParent(Node node) {
       if (root==null){
           return null;
       }else if (root==node){
           return root;
       }
       else{
           return root.findParent(node);
       }

    }
}

TestAVLTree类

package com.wuxudong.AVLTree;

public class TestAVLTree {
    public static void main(String[] args) {
        int [] arr=new int[] {8,5,9,4,6,7};
        AVLTree tree=new AVLTree();
        for (int i:arr){
            tree.add(new Node(i));
        }
        //System.out.println(tree.root);
        //tree.midShow();
        Node node= tree.search(6);
        //System.out.println(node.value);

        //删除节点
        //tree.deleteNode(12);
        //tree.midShow();

        System.out.println(node.height());

    }
}

  • 16
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值