数据结构之:平衡二叉树

一、 平衡二叉树概述

平衡二叉树(AVL树)按个人理解其实是对二叉排序树的一个升级,它其实是解决二叉排序树的一个缺陷,那么二叉排序树存在怎样的缺陷?我们知道二叉排序的查找效率是相对比较高的,不过对于下图这种二叉排序树,它的查找效率并不会提升。
在这里插入图片描述

平衡二叉树的出现就是为了解决这种缺陷问题,对我们的二叉树做一个平衡,以便保证它的查询效率,那怎样才能算是一棵平衡二叉树呢?我们这样规定:对于任何一个二叉排序树的非叶子节点,它的左子树和右子树的高度差绝对值不超过1,我们称这中二叉排序树为平衡二叉树。将二叉排序树转换称平衡二叉树有单旋转和双旋转两种方式,接下来我们来介绍这两种转平衡二叉树的方式。

二、平衡二叉树单旋转

1、右旋转

我们看下图的二叉排序树结构:
在这里插入图片描述
我们看到左侧的二叉排序树中,权值为6的这棵二叉排序树不平衡,因为它的左子树高度为2,右子树高度为0。如果是二叉排序树的左子树高度比右侧大,那么我们以这颗树的不平衡点(图中是权值为6的点)进行顺时针旋转(右旋转),以保持树的平衡。

2、右旋转

同样,如下图所示,权值为6的这棵二叉排序树不平衡,因为它的右子树高度为2,左子树高度为0。如果是二叉排序树的右子树高度比左侧大,那么我们以这颗树的不平衡点(图中是权值为6的点)进行逆时针旋转(左旋转),以保持树的平衡。
在这里插入图片描述

三、平衡二叉树双旋转

但是有这样一种情况,如下图所示,这棵不平衡二叉树,单单只进行一次旋转还是达不到平衡的状态,需要进行两次旋转才能达到平衡状态,我们称这种旋转方式为双旋转。
在这里插入图片描述

四、代码实现平衡二叉树的单、双旋转

package balancetree;

/**
 * 二叉排序树
 */
public class SortNode {
    private int value;
    private SortNode leftNode;
    private SortNode rightNode;

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

    public int getValue() {
        return value;
    }

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

    public SortNode getLeftNode() {
        return leftNode;
    }

    public void setLeftNode(SortNode leftNode) {
        this.leftNode = leftNode;
    }

    public SortNode getRightNode() {
        return rightNode;
    }

    public void setRightNode(SortNode rightNode) {
        this.rightNode = rightNode;
    }

    /**
     * 添加二叉排序树
     *
     * @param node
     */
    public void add(SortNode node) {
        if (node == null) {
            return;
        }
        //判断当前节点的大小
        if (node.getValue() < this.getValue()) {
            if (this.getLeftNode() == null) {
                this.setLeftNode(node);
            } else {
                this.getLeftNode().add(node);
            }
        } else {
            if (this.getRightNode() == null) {
                this.setRightNode(node);
            } else {
                this.getRightNode().add(node);
            }
        }
        //查询是否是平衡二叉树
        //进行右旋转
        if (leftHeigtht() - rightHeigth() >= 2) {
            //双旋转
            if (leftNode!=null&&leftNode.leftHeigtht()<leftNode.rightHeigth()){
                leftNode.leftRatate();
            }else {
                //当前节点变成左节点的右节点
                rightRatate();
            }

        } else {
            //双旋转
            if (rightNode!=null&&rightNode.rightHeigth()<rightNode.leftHeigtht()){
                rightNode.rightRatate();
            }else {
                //左旋转
                leftRatate();
            }

        }
    }

    /**
     * 左旋转
     */
    private void leftRatate() {
        SortNode node = new SortNode(this.getValue());

        node.setLeftNode(this.getLeftNode());

        node.setRightNode(this.getRightNode().getLeftNode());

        this.setValue(this.getRightNode().getValue());

        this.setRightNode(this.getRightNode().getRightNode());

        this.setLeftNode(node);

    }

    /**
     * 右旋转
     */
    private void rightRatate() {
        SortNode node = new SortNode(this.getValue());
        //当前节点的右节点赋值给新节点的右节点
        node.setRightNode(this.getRightNode());
        //将新节点加入当前节点的左节点的右子树
        node.setLeftNode(this.getLeftNode().getRightNode());
        //将当前节点的值换成左子节点的值
        this.setValue(this.getLeftNode().getValue());
        //将当前节点指向左节点的左节点
        this.setLeftNode(this.getLeftNode().getLeftNode());
        //将当前节点的右子树设置为新节点
        this.setRightNode(node);

    }

    /**
     * 左子树高度
     *
     * @return
     */
    public int leftHeigtht() {
       return this.getLeftNode()!=null?height():0;
    }

    /**
     * 右子树高度
     *
     * @return
     */
    public int rightHeigth() {
        return this.getRightNode()!=null?height():0;
    }

    /**
     * 返回前台节点的高度
     *
     * @return
     */
    public int height() {
        SortNode leftNode = this.getLeftNode();
        SortNode rightNode = this.getRightNode();
        return Math.max(leftNode == null ? 0 : leftNode.height(), rightNode == null ? 0 : rightNode.height()) + 1;
    }


    /**
     * 中序遍历二叉排序树
     */
    public void middleShow(SortNode node) {
        if (node == null) {
            return;
        }
        middleShow(node.getLeftNode());
        System.out.println(node.getValue());
        middleShow(node.getRightNode());
    }

    /**
     * @param value
     * @return
     */
    public SortNode search(int value) {
        if (this.getValue() == value) {
            return this;
        }
        if (this.getValue() > value) {
            return this.getLeftNode().search(value);
        }
        if (this.getValue() < value) {
            return this.getRightNode().search(value);
        }

        return null;
    }

    /**
     * 搜索父节点
     *
     * @param value
     */
    public SortNode searchParent(int value) {
        if (this.getLeftNode() != null && this.getLeftNode().getValue() == value ||
                this.getRightNode() != null && this.getRightNode().getValue() == value) {
            return this;
        } else {
            if (this.value < value && this.getLeftNode() != null) {
                return this.getLeftNode().searchParent(value);
            }
            if (this.value > value && this.getRightNode() != null) {
                return this.getRightNode().searchParent(value);
            }
        }
        return null;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章