數據結構之:平衡二叉樹

一、 平衡二叉樹概述

平衡二叉樹(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;
    }
}

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