平衡二叉樹代碼實現(xiàn)

一、 為什么會有平衡二叉樹

二叉查找樹雖然在效率上已經(jīng)很高了,但是效率并不是最高的,而且給出一列數(shù)字,我們可以構(gòu)造出多個二叉查找樹出來;不同的二叉查找樹因為樹的深度不同,效率不一樣,因此平衡二叉樹就是解決這個問題的,效率最高,構(gòu)造出來的二叉樹唯一;

二、平衡二叉樹定義

或者是一顆空樹,或者同時具有如下的性質(zhì):

  1. 他的左子樹和右子樹都是平衡二叉樹;
  2. 左子樹和右子樹的深度之差的絕對值不超過1;
平衡因子:一個的左子樹深度減去他的右子樹的深度。則平衡二叉樹的特點可以描述為:平衡二叉樹所有節(jié)點的平衡因子只可能為-1、0、1。

三、研究平衡二叉樹的目的

隨著節(jié)點的插入,不可避免的會破壞平衡二叉樹的結(jié)構(gòu),因此我們必須讓之回到平衡二叉樹的狀態(tài);
而且我們只能使用暴力的方式來使二叉樹重新回到平衡狀態(tài),即每插入一個節(jié)點,就進行一次調(diào)整,
研究平衡二叉樹就是研究這個調(diào)整的過程;


四、 平衡二叉樹代碼實現(xiàn)

public class AVLTree<E> {

    //標記左邊高,需要調(diào)整
    public static final int LEFT_HIGH = 1;
    //標記右邊高,需要調(diào)整
    public static final int RIGHT_HIGH = -1;
    //標記兩邊一樣高,不需要調(diào)整
    public static final int EQUAL_HIGH = 0;

    private TreeNode<E> root;

    private int size;

    /**
     * 插入一個元素,同時需要計算平衡因子,檢查平衡情況,做出旋轉(zhuǎn)調(diào)整
     * @param element
     * @return
     */
    public boolean insertElement(E element) {
        TreeNode<E> t = root;
        //一個節(jié)點都沒有,構(gòu)造節(jié)點,作為根節(jié)點
        if (t == null) {
            t = new TreeNode<>(element, null);
            root = t;
            size++;//其實現(xiàn)在size=1;等價于size=1;
            return true;
        }
        //如果走到這里,說明已經(jīng)有了跟節(jié)點,就需要先判斷插入的位置
        //這里隱含了一個前提條件,在插入之前,整棵樹已經(jīng)平衡了,
        //實際上這個條件是一定滿足的,因為在插入之后,就會判斷樹是否是平衡的

        //用來記錄比較樹的平衡度的變量
        int comparator = 0;
        //保存父節(jié)點
        TreeNode<E> parent;
        //因為是泛型,不能對象的大小,就通過比較器來實現(xiàn)比較大小
        //? super E: E或者E的父類 ? 這里是不是有問題,因該是E或者E的子類
        Comparable<? super E> e = (Comparable<? super E>) element;
        do {
            parent = t;
            //把當前結(jié)點和父節(jié)點比較大小,
            comparator = e.compareTo(t.element);
            if (comparator < 0) {//說明e小,王parent的左子樹上走
                t = t.leftChild;
            } else if (comparator > 0) {
                t = t.rightChild;
            } else {
                //相等就不需要插入
                return false;
            }
        } while (t != null);
        //while循環(huán)結(jié)束之后,就找到了需要插入節(jié)點的位置,即在那個節(jié)點下插入,
        // 但是還不能確定是插入在這個節(jié)點的左邊,還是右邊,這個需要判斷
        TreeNode<E> child = new TreeNode<>(element, parent);
        //插入左邊還是右邊
        if (comparator < 0) {
            //插入左邊
            parent.leftChild = child;
        } else {
            //插入右邊
            parent.rightChild = child;
        }
        //節(jié)點的位置已經(jīng)找到了,并且成功插入,接下來就要判斷新的樹是否平衡了
        //因為在插入之前樹已經(jīng)是平衡的了,所以如果樹是不平衡的,一定是因為新插入的節(jié)點引起的,
        //因此采用回溯法來判斷新插入的節(jié)點的父節(jié)點,爺爺節(jié)點是否平衡
        while (parent != null) {
            comparator = e.compareTo(parent.element);
            if (comparator < 0) {
                //相當于插在parent的左子樹上,因此parent的平衡因子+1
                parent.balance++;
            } else {
                parent.balance--;
            }
            if (parent.balance == 0) {
                //即插入的節(jié)點使得樹平衡了,說明插入的節(jié)點不影響樹的平衡性
                break;
            }
            //某一個節(jié)點的平衡度最大值只能為2,可能出現(xiàn)的值為-2,-1,0,1,2
            //當為-2,2時,需要調(diào)整,這里才出現(xiàn)問題
            if (Math.abs(parent.balance) == 2) {
                fixAfterInsert(parent);
            }
            //如果當前節(jié)點沒有問題,就接著回溯
            parent = parent.parent;
        }
        size++;
        return true;
    }

    /**
     * 根據(jù)某個不平衡的節(jié)點對樹進行旋轉(zhuǎn),使其平衡
     * @param parent
     */
    private void fixAfterInsert(TreeNode<E> parent) {
        if (parent.balance == 2) {
            //說明左邊高,要進行做平衡操作
            leftBalance(parent);
        } else if (parent.balance == -2) {
            //說明右邊高,要進行右平衡操作
            rightBalance(parent);
        }

    }

    private void rightBalance(TreeNode<E> t) {
        TreeNode rc = t.rightChild;
        switch (rc.balance) {
            case LEFT_HIGH:
                TreeNode lc = rc.leftChild;
                switch (lc.balance) {
                    case LEFT_HIGH:
                        t.balance = EQUAL_HIGH;
                        rc.balance = RIGHT_HIGH;
                        lc.balance = EQUAL_HIGH;
                        break;
                    case RIGHT_HIGH:
                        t.balance = LEFT_HIGH;
                        rc.balance = EQUAL_HIGH;
                        lc.balance = EQUAL_HIGH;
                        break;
                    case EQUAL_HIGH:
                        t.balance = EQUAL_HIGH;
                        rc.balance = EQUAL_HIGH;
                        lc.balance = EQUAL_HIGH;
                        break;
                }
                rightRotate(t.rightChild);
                leftRotate(t);
                break;
            case RIGHT_HIGH:
                leftBalance(t);
                //旋轉(zhuǎn)之后節(jié)點的平衡度發(fā)生了變化
                rc.balance = EQUAL_HIGH;
                t.balance = EQUAL_HIGH;
                break;
            case EQUAL_HIGH:
                break;
        }
    }

    /**
     * 節(jié)點t左邊的子樹過高
     * @param t
     */
    private void leftBalance(TreeNode<E> t) {
        TreeNode<E> lc = t.leftChild;
        //只知道lc的平衡度除了問題,但是不知道是那種情況,是lc的左邊,右邊,還是左右平衡,因此需要進行判斷
        switch (lc.balance) {
            case LEFT_HIGH://lc的左邊出了問題,直接進行右旋,但是是旋轉(zhuǎn)t的整個部分
                rightRotate(t);
                lc.balance = EQUAL_HIGH;
                t.balance = EQUAL_HIGH;
                break;
            case RIGHT_HIGH:
                TreeNode rc = lc.rightChild;
                switch (rc.balance) {
                    case LEFT_HIGH:
                        lc.balance = EQUAL_HIGH;
                        t.balance = RIGHT_HIGH;
                        rc.balance = EQUAL_HIGH;
                        break;
                    case RIGHT_HIGH:
                        t.balance = EQUAL_HIGH;
                        rc.balance = EQUAL_HIGH;
                        lc.balance = LEFT_HIGH;
                        break;
                    case EQUAL_HIGH:
                        t.balance = EQUAL_HIGH;
                        lc.balance = EQUAL_HIGH;
                        rc.balance = EQUAL_HIGH;
                        break;
                }
                //統(tǒng)一旋轉(zhuǎn)
                leftRotate(t.leftChild);
                rightRotate(t);
                break;
            case EQUAL_HIGH:
                break;
        }
    }

    private void leftRotate(TreeNode p) {
        if (p != null) {
            TreeNode rc = p.rightChild;
            p.rightChild = rc.leftChild;//把中間夾的多余的元素鏈接到p的右下
            if (rc.leftChild != null) {
                rc.leftChild.parent = p;
            }

            rc.parent = p.parent;//rc旋轉(zhuǎn)過來作為新樹的節(jié)點,任然連著以前的父節(jié)點
            if (p.parent == null) {
                root = rc;
            } else if (p == p.parent.leftChild) {
                p.parent.leftChild = rc;
            } else if (p == p.parent.rightChild) {
                p.parent.rightChild = rc;
            }
            rc.leftChild = p;
            p.parent = rc;
        }
    }

    private void rightRotate(TreeNode<E> p) {
        if (p != null) {
            TreeNode lc = p.leftChild;
            p.leftChild = lc.rightChild;
            if (lc.rightChild != null) {
                lc.rightChild.parent = p;
            }
            lc.parent = p.parent;
            if (p.parent == null) {
                root = lc;
            } else if (p == p.parent.leftChild) {
                p.parent.leftChild = lc;
            } else if (p == p.parent.rightChild) {
                p.parent.rightChild = lc;
            }
            lc.rightChild = p;
            p.parent = lc;
        }
    }

    private class TreeNode<E> {
        private E element;//節(jié)點的數(shù)據(jù)域
        private int balance;//節(jié)點的平衡因子,如果絕對值大于1,就表示需要調(diào)整
        private TreeNode leftChild;
        private TreeNode rightChild;
        private TreeNode parent;

        public TreeNode(E element, TreeNode parent) {
            this.element = element;
            this.parent = parent;
        }

        @Override
        public String toString() {
            //打印當前結(jié)點以及平衡因子
            return element + ",BF:" + balance;
        }

        public E getElement() {
            return element;
        }

        public void setElement(E element) {
            this.element = element;
        }

        public int getBalance() {
            return balance;
        }

        public void setBalance(int balance) {
            this.balance = balance;
        }

        public TreeNode getLeftChild() {
            return leftChild;
        }

        public void setLeftChild(TreeNode leftChild) {
            this.leftChild = leftChild;
        }

        public TreeNode getRightChild() {
            return rightChild;
        }

        public void setRightChild(TreeNode rightChild) {
            this.rightChild = rightChild;
        }

        public TreeNode getParent() {
            return parent;
        }

        public void setParent(TreeNode parent) {
            this.parent = parent;
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容