平衡二叉树的思路记录

平衡二叉树的删与我前一篇文章《排序二叉树的思路记录》一致,在此不再描述。

今天来谈谈平衡二叉树的添加,它与排序二叉树有所不同,在每次添加后,有两种情况

情况一、如果左子节点的高度-右子节点的高度>1,则表明左边长,需要右旋转。(这属于单旋转内容),当左子节点的右边的高度>左子节点的左边的高度,则还需要先将左子节点进行左旋转。(这属于双旋转内容) 216-222行代码

情况二、如果右子节点的高度-左子节点的高度>1,则表明右边长,需要左旋转。(这属于单旋转内容),当右子节点的左边的高度>左子节点的右边的高度,则还需要先将右子节点进行右旋转。 (这属于双旋转内容) 224-230行代码

对于为什么会产生双旋转的内容,可以看文章后面进行刨析。

方法阐述:

①leftRoute:当前节点的左子节点长,右旋转
②RightRoute:当前节点的右子节点长,左旋转
③height:当前节点的高度
④RightHeight:当前节点的右子节点高度
⑤leftHeight:当前节点的左子节点高度

现在介绍为什么会有双旋转的内容:

先看图片,如果对于10的左子节点的右边>10的左子节点的左边,还不进行双旋转会产生的后果,就是单旋转后,还是不符合平衡二叉树的规范,所以我们需要先将10的左子节点(节点7先进行左旋转,然后再进行节点10的右旋转就可以变成图二的样子)

 最后贴上实现代码:

package ysh.tree.AvlTree;

public class AVLTreeDemo {
    public static void main(String[] args) {
    //int[] arr = {4,3,6,5,7,8};
    //int[] arr = { 10, 12, 8, 9, 7, 6 };
        int[] arr = { 10, 11, 7, 6, 8, 9 };
    //创建一个 AVLTree 对象
        AvlTree avlTree = new AvlTree();
    //添加结点
        for(int i=0; i < arr.length; i++) {
            avlTree.add(new Node(arr[i]));
        }
    //遍历
        System.out.println("前序遍历");
        avlTree.PreOrder();
        System.out.println("在平衡处理~~");
        System.out.println("树的高度=" + avlTree.getRoot().height()); //3
        System.out.println("树的左子树高度=" + avlTree.getRoot().leftHeight()); // 2
        System.out.println("树的右子树高度=" + avlTree.getRoot().RightHeight()); // 2
        System.out.println("当前的根结点=" + avlTree.getRoot());//8
          }
}
class AvlTree {
    private Node root;

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }

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

    public void PreOrder() {
        if(root==null){
            System.out.println("树没有节点");
        }else{
            root.PreOrder();
        }
    }
    //查找要删除的结点
    public Node findNode(int value) {
        if(root == null) {
            return null;
        } else {
            return root.findNode(value);
        }
    }
    //查找父结点
    public Node findParentNode(int value) {
        if(root == null) {
            return null;
        } else {
            return root.findParentNode(value);
        }
    }
    public void delNode(int i) {
        if(root==null){
            System.out.println("树没有节点可以删了");
        }else if(root.getLeft()==null&&root.getRight()==null){//整个树只有root这个节点可以删除
            root=null;
        }else{
            Node node = findNode(i);
            if(node==null){
                System.out.println("没有可以删除的节点");
            }else{
                Node parentNode = findParentNode(i);
                if(parentNode==null){//删除节点有四种情况①(删除的是父节点)如果没有这个父节点,则只有一种可能,就是父节点是要删除的节点,属于有两个子节点的情况,不过也有特殊,需要改root
                    root.setValue(findMax(root.getLeft()));
                }else{//删除子节点的另外三种情况,②删除的节点是叶子节点③删除的节点有两个子节点④删除的节点有一个子节点
                    if(node.getLeft()==null&&node.getRight()==null) {//第二种情况
                        if(node.getValue()<parentNode.getValue()){
                            parentNode.setLeft(null);
                        }else{
                            parentNode.setRight(null);
                        }
                    }else if(node.getLeft()!=null&&node.getRight()!=null){//第三种
                        int max = findMax(node.getLeft());
                        node.setValue(max);
                    }else{//第四种,也分四种情况,1.1 要删除的节点在父节点的左边且要删除的节点下面的节点在左边 1.2要删除的节点在父节点的左边且要删除的节点下面的节点在右边
                        //2.1 要删除的节点在父节点的右边且要删除的节点下面的节点在左边  2.2要删除的节点在父节点的右边且要删除的节点下面的节点在右边
                        if(node.getValue()>parentNode.getValue()){  //2.1 2.2的情况
                            if(node.getLeft()==null){
                                parentNode.setRight(node.getRight());
                            }else{
                                parentNode.setRight(node.getLeft());
                            }
                        }else{   //1.1 1.2的情况
                            if(node.getLeft()==null){
                                parentNode.setLeft(node.getRight());
                            }else{
                                parentNode.setLeft(node.getLeft());
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     *  当删除有两个子节点的节点时,要么找到左子树的最大值,要么找到右子树的最小值
     * @param node  以node为子树
     * @return    找到以node为子树的,其子树下面的最大值
     */
    public int findMax(Node node){
        Node temp=node;
        while(temp.getRight()!=null){
            temp=temp.getRight();
        }
        delNode(temp.getValue());
        return temp.getValue();
    }
}
class Node {
    private int value;
    private Node left;
    private Node right;

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

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "Node{" +
                "value=" + value +
                '}';
    }
    //左子树高度
    public int leftHeight(){
        if(left==null){
            return 0;
        }else{
            return left.height();
        }
    }
    //右子树高度
    public int RightHeight(){
        if(right==null){
            return 0;
        }else{
            return right.height();
        }
    }
    public int height(){
        return Math.max(left==null?0:left.height(),right==null?0:right.height())+1;
    }
    //左旋转
    public void leftRoute(){
        Node newnode = new Node(value);
        newnode.setLeft(left);
        newnode.setRight(right.left);
        value=right.value;
        right=right.right;
        left=newnode;
    }
    //右旋转
    public void RightRoute(){
        Node newnode = new Node(value);
        newnode.setRight(right);
        newnode.setLeft(left.right);
        value=left.value;
        left=left.left;
        right=newnode;
    }
    public void add(Node root){
        //如果要添加的节点小于当前节点
        if(root.value<this.value){
            if(this.left==null){//如果为空,则直接插入
                this.left=root;
            }else{//如果不为空,则往左递归
                left.add(root);
            }
        }else{//要添加的节点大于等于当前节点
            if(this.right==null){//如果为空,则直接插入
                this.right=root;
            }else{//如果不为空,则往右递归
                right.add(root);
            }
        }

        if(leftHeight()-RightHeight()>1){
            //左边长,右旋转
            //如果左边子节点的右边长,则又需要子节点左旋转先,形成双旋转模型,否则就会旋转过去后还是不符合
            if(left!=null&&left.RightHeight()>left.leftHeight()){
                left.leftRoute();
            }
            RightRoute();

        }else if(RightHeight()-leftHeight()>1){
            //右边长,左旋转
            //如果右边子节点的左边长,则又需要子节点右旋转先,形成双旋转模型,否则就会旋转过去后还是不符合
            if(right!=null&&right.leftHeight()>right.RightHeight()){
                right.RightRoute();
            }
            leftRoute();
        }
    }
    public void PreOrder() {
        System.out.println(this);
        if(left!=null){
            left.PreOrder();
        }
        if(right!=null){
            right.PreOrder();
        }
    }



    /**
     * 找到要删除的节点
     * @param i   要删除节点的值
     * @return    返回要删除的节点
     */
    public Node findNode(int i){
        if(this.value==i){
            return this;
        }
        if(i<this.value){//要找的值小于当前值
            if(left!=null){
                return left.findNode(i);
            }
        }else{//要找的值大于等于当前值
            if(right!=null){
                return right.findNode(i);
            }
        }
        return null;
    }
    /**
     *
     * @param i 要删除节点的值
     * @return    要删除节点的父节点
     */
    public Node findParentNode(int i){
        if((left!=null&&left.value==i)||(right!=null&&right.value==i)){//如果当前节点的左右节点不为空且是要找到值,则直接返回找到的父节点
            return this;
        }
        if(i<this.value){//如果要删除的值小于当前节点
            if(left!=null) {
                return   left.findParentNode(i);
            }
        }else{//如果要删除的值大于等于当前节点
            if(right!=null) {
                return   right.findParentNode(i);
            }
        }
        return null;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值