數據結構-平衡二叉樹

平衡二叉樹的重點在於對不平衡的進行旋轉從而使它達到平衡.數據結構

下面是我理解的平衡二叉樹的操做總結:ide

平衡因子(BF):
 這是一個描述平衡度的一個量,計算的方式爲 左子樹的深度-右子樹的深度。this

咱們能夠從BF中就能知道左子樹和右子樹之間的平衡程度。spa

插入數據3d

平衡二叉樹最複雜的就是將數據插入到樹中了,由於要涉及到位置的調整。對於位置的調整在平衡二叉樹中成爲樹的旋轉.根據平衡因子的狀態分爲左旋和右旋.code

那何時須要進行旋轉呢?blog

這個問題確實值得思考,通常都是在平衡因子的絕對值大於1的時候就須要進行旋轉了,也就是說左右子樹的深度相差超過了1.get

那從什麼地方作爲跟節點進行旋轉呢?it

這裏有一個術語叫作最小不平衡子樹,就是平衡因子絕對值大於1,而且最接近葉子節點的。io

咱們旋轉的時候,只須要對最小不平衡子樹進行旋轉就能夠了。

左旋:

當平衡因子爲正數的時候而且大於1的時候,進行左旋,左旋的方式爲:
根節點的左子樹的右子樹做爲根節點的右子樹,根節點做爲左子樹的右子樹。

 

 

 右旋:

當平衡因子爲負數的時候,而且小於-1的時候進行右旋,右旋的方式爲:
將根節點的右節點的左子樹做爲根節點的右子樹.
根節點做爲跟節點的右節點的左子樹。

 

注意: 

上面兩種實例根節點和子節點都是同一符號的,因此簡單的進行左旋或者右旋就能夠了。以下圖:

,可是若是咱們遇到符號不相同的狀況下,須要進行兩次旋轉,以下圖:

 

這種狀況下,第一次旋轉是將C做爲根節點右旋,以後再進行左旋.

咱們只須要記住正數的時候進行右旋,負數的時候進行左旋便可。

 上面的原理講完了,下面是具體的JAVA代碼實現:

package com.hotusm.datastructure.tree;

/**
 * @author luqibao
 * @date 2017/3/31
 */
public class AVLTree {


    /**
     * 平衡因子所屬的狀態
     */
    private static final int LH = 1;   //左邊高
    private static final int EH = 0;   //同樣高
    private static final int RH = -1;  //右邊高


    private TreeNode root;  //樹的根


    /**
     * 向平衡二叉樹插入節點
     *
     * @param data
     */
    public void insertNode(int data) {

        if (this.root == null) {
            this.root = new TreeNode(null, null, EH, data, null);
            return;
        }
        insertAVLNode(this.root, data);

    }


    /**
     * 進行右旋
     *
     * @param treeNode 須要旋轉的根
     */
    /*
     * 右旋
     * 將根的左子樹的右子樹做爲根的左子樹
     * 左子樹的右子樹指向根(最後左子樹變爲了根,根變爲了右子樹)
     */
    private void rRotate(TreeNode treeNode) {
        TreeNode root = treeNode.getLeft();
        if (treeNode == this.root) {
            this.root = root;
        }
        treeNode.setLeft(root.getRight());
        root.setRight(treeNode);
    }

    /**
     * 進行左旋
     *
     * @param treeNode 須要旋轉的根
     */
    /*
    * 左旋
    * 將根的右子樹的左子樹做爲根的右子樹
    * 右子樹的左子樹指向根(最後右子樹變爲個根,根變爲了左子樹)
    * */
    private void lRotate(TreeNode treeNode) {
        TreeNode root = treeNode.getRight();
        if (treeNode == this.root) {
            this.root = root;
        }
        treeNode.setRight(root.getLeft());
        root.setLeft(treeNode);
    }

    /**
     * 左平衡旋轉(左邊平衡因子太大的緣由  須要向右移動)
     *
     * @param root
     */
    private void leftBalance(TreeNode root) {
        TreeNode leftNode = root.getLeft();
        switch (leftNode.getBf()) {
            case LH:
                root.setBf(EH);
                leftNode.setBf(EH);
                rRotate(root);
                break;
            //若是是這種狀況  根和左子樹平衡因子不是同符號的  因此須要兩次的旋轉
            case RH:
                TreeNode doubleLeftNode = leftNode.getRight();// 左子樹的右子樹
                switch (doubleLeftNode.getBf()) {
                    case RH:
                        root.setBf(EH);
                        leftNode.setBf(LH);
                        break;
                    case EH:
                        root.setBf(EH);
                        leftNode.setBf(EH);
                        break;
                    case LH:
                        root.setBf(RH);
                        leftNode.setBf(EH);
                        break;
                }
                doubleLeftNode.setBf(EH);
                lRotate(leftNode);
                rRotate(root);
                break;
        }
    }

    /**
     * 右平衡旋轉 右邊平衡因子太大的緣由
     *
     * @param root
     */
    private void rightBalance(TreeNode root) {

        TreeNode rightNode = root.getRight();

        switch (rightNode.getBf()) {
            case RH:
                root.setBf(EH);
                rightNode.setBf(EH);
                lRotate(root);
                break;
            case LH: //若是是這種狀況 那麼根和右子樹的平衡因子不一樣符號 因此須要進行兩次的旋轉
                TreeNode doubleLeftNode = rightNode.getLeft();
                switch (doubleLeftNode.getBf()) {
                    case LH:
                        root.setBf(EH);
                        rightNode.setBf(RH);
                        break;
                    case EH:
                        root.setBf(EH);
                        rightNode.setBf(EH);
                        break;
                    case RH:
                        root.setBf(LH);
                        rightNode.setBf(EH);
                        break;
                }
                doubleLeftNode.setBf(EH);
                rRotate(rightNode);
                lRotate(root);
                break;
        }

    }

    /**
     * 向平衡二叉樹插入數據data
     * 若是增高那麼返回true  不然返回false
     *
     * @param data
     * @return
     */
    private boolean insertAVLNode(TreeNode root, int data) {
        boolean taller = false;
        if (root.getData() == data) {
            return false;
        }
        if (data < root.getData()) {
            if (root.getLeft()==null){
                TreeNode child=new TreeNode(null,null,EH,data,root);
                root.setLeft(child);
                if (root.getBf()==EH){
                    root.setBf(LH);
                    return true;
                }
                /*
                 * 在child 節點未插入到root的左子樹中的時候
                 * root的BF只能有兩種狀況 EH(左右都沒節點) 和 RH(有右葉子節點)
                 * 因此還有一種可能就是當時RH的時候 BF變爲EH
                 * */
                root.setBf(EH);
            }else {
                taller=insertAVLNode(root.getLeft(),data);
                if (taller){
                    switch (root.getBf()){
                        case LH:
                            leftBalance(root);
                            taller=false;
                            break;
                        case EH:
                            /*
                             *進行上一級的回溯
                             *      O
                             *    O   O
                             *  O  O
                             */
                            root.setBf(LH);
                            taller=true;
                            break;
                        default:
                            root.setBf(EH);
                            taller=false;
                    }
                }
            }
        } else {
            if (root.getRight()==null){
                TreeNode child=new TreeNode(null,null,EH,data,root);
                root.setRight(child);
                if (root.getBf()==EH){
                    root.setBf(RH);
                }
                /*
                * 和上面的相似,在右子樹插入到root以前 root的BF只有兩種狀況 EH(沒有左右節點) LH (只有左葉子節點)
                * */
                root.setBf(EH);
            }else {
                taller=insertAVLNode(root.getRight(),data);
                if (taller){
                    switch (root.getBf()){
                        case RH:
                            rightBalance(root);
                            taller=false;
                            break;
                        case LH:
                            root.setBf(EH);
                            taller=false;
                            break;
                        default:
                        /*
                         *這裏會進行回溯到更上的一級進行判斷 從而進行旋轉
                         *              O
                         *            O   O
                         *               O  O
                         */
                            root.setBf(RH);
                            taller=true;
                    }
                }
            }
        }
        return taller;
    }

    public static void main(String[] args) {
        testInsertAVLTree();
    }

    public static void testInsertAVLTree() {
        AVLTree avlTree = new AVLTree();
        avlTree.insertNode(1);
        avlTree.insertNode(2);
        avlTree.insertNode(3);
        avlTree.insertNode(4);
        avlTree.insertNode(5);

    }

    /**
     * 樹的節點
     */
    public static class TreeNode {

        private TreeNode left;
        private TreeNode right;
        private TreeNode parent;
        private int bf; //平衡因子
        private int data;

        public TreeNode(TreeNode left, TreeNode right, int bf, int data, TreeNode parent) {
            this.left = left;
            this.right = right;
            this.bf = bf;
            this.data = data;
            this.parent = parent;
        }

        public TreeNode getLeft() {
            return left;
        }

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

        public TreeNode getRight() {
            return right;
        }

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

        public int getBf() {
            return bf;
        }

        public void setBf(int bf) {
            this.bf = bf;
        }

        public int getData() {
            return data;
        }

        public TreeNode getParent() {
            return parent;
        }

        public void setParent(TreeNode parent) {
            this.parent = parent;
        }

        public void setData(int data) {
            this.data = data;
        }

        @Override
        public String toString() {
            return "TreeNode{" +
                    "left=" + left +
                    ", right=" + right +
                    ", bf=" + bf +
                    ", data=" + data +
                    '}';
        }
    }
}

代碼中進行了詳細的註釋,看起來應該是沒問題的。

參考:大話數據結構 第八章

相關文章
相關標籤/搜索