java 平衡二叉树分析原理及实现

目录

二叉树是什么?

平衡是什么?

新增不平衡有哪些情况?

最终不平衡原因有以下四种情况

针对不平衡该如何旋转?

情况1》右旋

条件:插入到不平衡节点的左子树的左子树上

 情况2》先左旋再右旋

条件:插入到不平衡节点左子树的右子树上

情况3》先右旋再左旋

条件:插入到不平衡节点右子树的左子树上

情况4》左旋

条件:插入到不平衡节点右子树的右子树上

平衡演示

当一棵树越来越大时,这个时候要把大树想成小树,对应上面的旋转就可以了,这里只说明一种情况了

最终旋转的条件为

树结点删除

操作说明

代码实现

树结构代码

测试代码


二叉树是什么?

二叉树是一种树的结构,我们通过将数据以树的结构进行存储,方便的是我们对数据进行检索。

但是一棵不平衡的二叉树,如果进行数据检索,性能来说会丢失,如果要达到最优检索效果,需要一棵平衡的二叉树。

平衡是什么?

平衡就是树的每一个结点,相对的左右子树深度差值不能大于1或小于-1

新增不平衡有哪些情况?


最终不平衡原因有以下四种情况

最终不平衡
最终不平衡原因有以下四种情况原因有以下四种情况

针对不平衡该如何旋转?

情况1》右旋

条件:插入到不平衡节点的左子树的左子树上

 情况2》先左旋再右旋

条件:插入到不平衡节点左子树的右子树上


情况3》先右旋再左旋

条件:插入到不平衡节点右子树的左子树上


情况4》左旋

条件:插入到不平衡节点右子树的右子树上

平衡演示

 

当一棵树越来越大时,这个时候要把大树想成小树,对应上面的旋转就可以了,这里只说明一种情况了

最终旋转的条件为

旋转方向说明
右旋不平衡节点左子树最深,左子树的左子树最深
先左旋再右旋不平衡节点左子树最深,左子树的右子树最深
先右旋再左旋不平衡节点右子树最深,右子树的左子树最深
左旋不平衡节点右子树最深,右子树的右子树最深

树结点删除

位置情况
图中1没有左子树,也没有右子树
图中2只有一个左子树
图中3只有一个右子树
图中4有左子树,也有右子树

操作说明

图位置 
图中1

1.直接删除20节点

2.15结点右子树指向设置为null

3. 从20的父结点开始向上走,发现不平衡结点就旋转,直到走到根结点为止

图中2

1.让6结点指向父结点10的引用,改成10指向父结点15的引用

2.15结点左结点的引用,改成指向6结点的引用

3.删除结点10,然后从10的父结点开始向上走,发现不平衡结点就旋转,直到走到根结点为止

图中3

1.让99结点指向父结点90的引用,改成90指向父结点80的引用

2.80结点右结点的引用,改成指向99结点的引用

3.删除结点90,然后从90的父结点开始向上走,发现不平衡结点就旋转,直到走到根结点为止

图中4

1.首先找50结点右子树,最左边的结点70

2. 把70结点的值保存一下,然后删除70结点

3. 从70的父结点开始向上走,发现不平衡结点就旋转,直到走到根结点为止

4.将70结点的值把50结点值覆盖掉


代码实现

树结构代码

package com.wxl.practices.tree;

public class Tree<K extends Comparable, V> {

    private TreeNode<K, V> root;  //根结点
    private int size;

    /**
     * 当前树上元素个数
     * @return
     */
    public int size() {
        return size;
    }

    /**
     * 树结点的结构
     * @param <K>
     * @param <V>
     */
    class TreeNode<K, V>{
        private TreeNode<K, V> parent;
        private K key;
        private V value;
        private TreeNode<K, V> left;
        private TreeNode<K, V> right;

        public TreeNode(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public TreeNode(TreeNode<K, V> parent, K key, V value) {
            this(key, value);
            this.parent = parent;
        }
    }

    /**
     * find方法为返回多个值创建的返回值类
     */
    private class FindResult {
        public boolean isFind;
        public TreeNode<K, V> node;
        public boolean isLeft;

        public FindResult(boolean isFind, TreeNode<K, V> node) {
            this.isFind = isFind;
            this.node = node;
        }

        public FindResult(boolean isFind, TreeNode<K, V> node, boolean isLeft) {
            this.isFind = isFind;
            this.node = node;
            this.isLeft = isLeft;
        }
    }

    /**
     * 寻找树结点,存在或不存在,以下新增或删除会用到
     * @param key
     * @return
     */
    private FindResult find(K key) {
        TreeNode<K, V> node = root;
        int rst = 0;
        do {
            rst = key.compareTo(node.key);
            if (rst == 0) {
                return new FindResult(true, node);
            } else if (rst > 0) {
                if (node.right != null) {
                    node = node.right;
                    continue;
                }
            } else if (rst < 0) {
                if (node.left != null) {
                    node = node.left;
                    continue;
                }
            }
            break;
        } while (true);
        return new FindResult(false, node, rst < 0 ? true : false);
    }

    public void add(K key, V value) {
        if(root == null) {
            root = new TreeNode(key, value);
        } else {
            FindResult findResult = find(key);
            if (findResult.isFind) {
                findResult.node.value = value;
            } else {
                TreeNode<K, V> newNode = new TreeNode(findResult.node, key, value);
                if (findResult.isLeft) {
                    findResult.node.left = newNode;
                } else {
                    findResult.node.right = newNode;
                }
                //每一次新加完结点的时候都要判断有没有因为新增结点,导至树不平衡的情况
                balanceTree(findResult.node);
            }
        }
        size ++;
    }

    /**
     * 调用平衡树方法
     */
    private void balanceTree(TreeNode<K, V> node) {
        int leftRightTreeDValue = 0;
        TreeNode<K, V> leftNode;
        TreeNode<K, V> rightNode;
        while (node != null) {
            leftRightTreeDValue = leftRightTreeDValue(node);
            if (leftRightTreeDValue > 1) {  //左边深并且不平衡
                leftNode = node.left;
                if(leftRightTreeDValue(leftNode) < 0) {
                    leftRotation(leftNode);
                }
                rightRotation(node);
            } else if (leftRightTreeDValue < -1) {  //右边深并且不平衡
                rightNode = node.right;
                if(leftRightTreeDValue(rightNode) > 0) {
                    rightRotation(rightNode);
                }
                leftRotation(node);
            }
            node = node.parent;
        }
    }

    /**
     * 计算要查询结点左右两个树的差值
     * @param node 树结点
     * @return
     */
    private int leftRightTreeDValue(TreeNode<K, V> node) {
        return countTreeDepth(node.left) - countTreeDepth(node.right);
    }

    /**
     * 计算一个树的深度
     * @param node
     * @return
     */
    private int countTreeDepth(TreeNode<K, V> node) {
        if (node == null) {
            return 0;
        }
        return 1 + Math.max(countTreeDepth(node.left), countTreeDepth(node.right));
    }

    /**
     * 左旋转
     * @param node
     */
    private void leftRotation(TreeNode<K, V> node) {
        TreeNode<K, V> rightNode = node.right;
        node.right = rightNode.left;
        if (null != rightNode.left) {
            rightNode.left.parent = node;
        }
        rightNode.parent = node.parent;
        node.parent = rightNode;
        rightNode.left = node;

        if (null == rightNode.parent) {
            this.root = rightNode;
        } else if (rightNode.parent.left == node) {
            rightNode.parent.left = rightNode;
        } else if (rightNode.parent.right == node) {
            rightNode.parent.right = rightNode;
        }
    }

    /**
     * 右旋转
     * @param node
     */
    private void rightRotation(TreeNode<K, V> node) {
        TreeNode<K, V> leftNode = node.left;
        node.left = leftNode.right;
        if (null != leftNode.right) {
            leftNode.right.parent = node;
        }

        leftNode.parent = node.parent;
        node.parent = leftNode;
        leftNode.right = node;

        if (null == leftNode.parent) {
            this.root = leftNode;
        } else if (leftNode.parent.left == node) {
            leftNode.parent.left = leftNode;
        } else if (leftNode.parent.right == node) {
            leftNode.parent.right = leftNode;
        }
    }

    /**
     * 删除结点
     * @param key
     */
    public void remove(K key) {
        FindResult findResult = find(key);
        if (!findResult.isFind) {
            return;
        }
        TreeNode<K, V> parentNode = findResult.node.parent;
        TreeNode<K, V> leftNode = findResult.node.left;
        TreeNode<K, V> rightNode = findResult.node.right;

        if (leftNode == null && rightNode == null) {
            relationNode(parentNode, findResult.node, null);
        } else if(leftNode != null && rightNode == null) {
            relationNode(parentNode, findResult.node, leftNode);
        } else if(leftNode == null && rightNode != null) {
            relationNode(parentNode, findResult.node, rightNode);
        } else {
            TreeNode<K, V> right = findRight(findResult.node);
            K rightKey = right.key;
            V rightValue = right.value;
            remove(right.key);
            findResult.node.key = rightKey;
            findResult.node.value = rightValue;
            return;
        }
        releaseNode(findResult.node);
        findResult.node = null;
        balanceTree(parentNode);
        size --;
    }

    /**
     *
     * @param parentNode 父结点
     * @param node 要删除的结点
     * @param resultNode 根据上面代码可见结点意思
     */
    private void relationNode(TreeNode<K, V> parentNode, TreeNode<K, V> node,
                              TreeNode<K, V> resultNode) {
        if(resultNode != null)
            resultNode.parent = node.parent;

        if(parentNode == null) {
            this.root = resultNode;
        } else if(parentNode.left == node) {
            parentNode.left = resultNode;
        } else if(parentNode.right == node) {
            parentNode.right = resultNode;
        }
    }

    /**
     * 寻找一个结点右子树的最左结点
     * @param node 要删除的结点
     * @return
     */
    private TreeNode<K, V> findRight(TreeNode<K, V> node) {
        TreeNode<K, V> rightNode = node.right;
        while (rightNode.left != null) {
            rightNode = rightNode.left;
        }
        return rightNode;
    }

    /**
     * 释放结点
     * @param node
     */
    private void releaseNode(TreeNode<K, V> node) {
        node.parent = null;
        node.key = null;
        node.value = null;
        node.left = null;
        node.right = null;
    }
}

测试代码

package com.wxl.practices.tree;

public class Test {
    public static void main(String[] args) {
        Tree<String, Integer> tr = new Tree<>();
        //新增
        tr.add("70", 1001);
        tr.add("50", 1002);
        tr.add("20", 1003);
        tr.add("10", 1004);
        tr.add("15", 1005);
        tr.add("80", 1006);
        tr.add("75", 1007);
        tr.add("90", 1008);
        tr.add("99", 1009);
        tr.add("76", 1010);
        tr.add("33", 1011);
        tr.add("39", 1012);
        System.out.println(tr.size());
        //删除
        tr.remove("50");
        tr.remove("90");
        tr.remove("39");
        tr.remove("75");
        tr.remove("80");
        tr.remove("99");
        System.out.println(tr.size());
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值