我所知道數據結構之平衡二叉樹

前言需求介紹


咱們從一個數列(1,2,3,4,5,6),來講明構成二叉排序樹的一些問題node

圖片.png

1.左子樹所有爲空, 從形式圖所看,更像一個單鏈表
2.查詢速度明顯下降(由於須要依次比較),不能發揮BST
的優點,由於每次還須要比較左子樹,其查詢速度比單鏈表還慢算法

那麼怎麼辦?ide

那麼像這樣的數列咱們能夠是用解決方案--->平衡二叉樹(AVL)性能

1、什麼是平衡二叉樹


基本介紹

1.平衡二叉樹也叫平衡二叉搜索樹(Self balancing binary searchtree)又被稱爲AVL樹, 能夠保證查詢效率較高。測試

有如下特色:
1.它是一顆空樹或它的左右兩個子樹的高度差絕對超過1
2.左右兩個子樹都是一棵平衡二叉樹。優化

平衡二叉樹的經常使用實現:紅黑樹、AVL(算法)、替罪羊樹、Treap、伸展樹等。this

哪些樹是AVL樹?爲何?

圖片.png

結合前面咱們介紹的AVL樹特色分析看看,如今你知道了嗎?
圖片.pngspa

簡單說來

平衡二叉樹之因此將二叉排序樹,調整爲平衡狀態,是爲了在二叉排序樹近似爲鏈的狀況下,加強其查找性能,下降時間複雜度。3d

常見調整方式


常見的二叉平衡樹調整平衡方法有:LL、LR、RR、RLcode

RR型介紹

image.png

當前這種狀況圖三,鏈式就須要平衡調整,不然則影響到查詢的效率

平衡調整:一個根節點與兩左右子節點的二叉排序樹(以下圖)

image.png

原本Mar節點再插入May時,還保持平衡:知足右子節點大於根節點

當插入麻煩節點Nov時平衡點被破壞,且Nov節點是在根節點的右子樹的右子樹上

根據二叉排序的特性:右子樹節點比當前節點大

咱們找到Mar、May、Nov的中間數,它們的大小關係是Mar<May<Nov

此時將May做爲根節點Mar做爲左子樹、Nov做爲右子樹進行調整

這時,這種插入即稱呼爲RR插入,平衡調整也成爲RR旋轉(右單轉)

image.png
image.png

LL型介紹

image.png

當插入麻煩節點Apr時平衡點被破壞,且Apr節點是在Mar節點的左子樹的左子樹上

咱們找到Mar、Aug、Apr的中間數,它們的大小關係是Apr<Aug<Mar

此時將Aug做爲根節點Apr做爲左子樹、Mar做爲右子樹進行調整

這時,這種插入即稱呼爲LL插入,平衡調整也成爲LL旋轉(左單轉)

固然插入的節點也多是左子節點或者右子節點

咱們發現其實進行旋轉調整的時候呢

不必定是根節點才進行旋轉。在中間的節點Mar也是能夠的

image.png

LR介紹

image.png

當插入麻煩節點Jan時平衡點被破壞,且Jan節點是在May節點的左子樹的右子樹上

咱們找到May、Aug、Mar的中間數,它們的大小關係是Aug<Mar<May

此時將Mar做爲根節點Aug做爲左子樹、May做爲右子樹

Mar>AugJan<Mar 根據特性Jan做爲Aug右子樹進行調整

這時,這種插入即稱呼爲LR插入,平衡調整也成爲LR旋轉

image.png

RL介紹

image.png

當插入麻煩節點Feb時平衡點被破壞,且Feb節點是在Aug節點的右子樹的左子樹上

咱們找到Jan、Aug、Dec的中間數,它們的大小關係是Aug<Dec<Jan

此時將Dec做爲根節點Aug做爲左子樹、Jan做爲右子樹

Jan>DecFeb>Dec 根據特性Feb做爲Jan左子樹進行調整

這時,這種插入即稱呼爲RL插入,平衡調整也成爲RL旋轉

image.png

LL、RR、LR、RL四種模式方法怎麼判別?


即看插入節點把誰破壞了,跟被破壞節點是什麼關係?

是左邊的左邊?右邊的右邊?仍是左邊的右邊?右邊的左邊?

可是須要注意的是:平衡調整後仍爲二叉排序樹

2、經過示例認識平衡二叉樹的右旋轉


給你一個數列{4,3,6,5,7,8},讓你可以高效的完成對數據的查詢和添加

那麼按照咱們以前的思路,先構建:一顆二叉排序樹

二叉排序樹的特色?

非葉子節點特色:左子節點的值比當前節點的值小,右子節點的值比當前節點的值大。
特別說明:若是有相同的值,能夠將該節點放在左子節點或右子節點

回顧構建二叉排序樹思路分析

  • 判斷左子節點的值是否比當前節點的值小
  • 不然判斷右子節點的值比當前節點的值大
  • 遞歸判斷是否符合左子節點、右子節點的條件

圖片.png

那麼咱們前面分析了在二叉排序樹近似爲鏈的狀況下

1.從形式圖所看,更像一個單鏈表
2.查詢速度明顯下降(由於須要依次比較),不能發揮BST的優點

因此咱們須要進行調整:平衡狀態加強其查找性能,下降時間複雜度

咱們發現這顆二叉排序樹左子樹高度爲1,右邊子樹高度爲3

image.png

此時不符合平衡二叉樹的特色:它是一顆空樹或它的左右兩個子樹的高度差絕對超過1

根據上面介紹的四種平衡調整模式介紹,目前比較符合的是RR旋轉

使用RR旋轉圖解案例思路分析

image.png

咱們結合上面的圖與RR旋轉的思路一塊兒來分析當前的案例

image.png

未插入節點8時,還保持平衡:知足右子節點大於根節點

當插入麻煩節點8時平衡點被破壞,且節點8是在根節點的右子樹的右子樹上

根據二叉排序的特性:右子樹節點比當前節點大

咱們找到四、六、7的中間數,它們的大小關係是 4 < 6 < 7

此時將 6 做爲根節點 4 做爲左子樹、 7 做爲右子樹進行調整

RR旋轉代碼實現思路分析

  • 建立一個新節點newNode等於當前根節點root,值相等

image.png

  • 新節點newNode的左子樹設置爲當前根節點root的左子樹

image.png

  • 新節點newNode的右子樹設置爲當前根節點root的右子樹的左子樹

image.png

  • 當前根節點root的值換爲右子節點的值

image.png

  • 當前根節點root的右子樹設置成根節點root的右子樹的右子樹

image.png

  • 當前根節點root的左子樹設置爲新節點

image.png

示例代碼實現

你們有沒有發現,節點與子樹之間的高度是關鍵的

並非說加入一個節點得時候就進行旋轉,而是左右兩個子樹的高度差絕對超過1纔去進行平衡調整

因此須要先完成事情是:統計當前樹的高度、統計與左子樹、或右子樹的高度

那麼咱們用代碼實踐來統計:樹的高度、左子樹高度、右子樹高度

(節點代碼、AVL代碼可參考二叉排序樹相關代碼)

class Node{

    int value;
    Node left;
    Node right;

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

    /**
     * @param value 但願刪除的結點的值
     * @return若是找到返回該結點,不然返回null
     */
    public Node search(int value) {

        if(value == this.value) { //找到就是該結點
            return this;
        } else if(value < this.value) {//若是查找的值小於當前結點,向左子樹遞歸查找
            //若是左子結點爲空
            if(this.left == null) {
                return null;
            }
            return this.left.search(value);
        } else { //若是查找的值不小於當前結點,向右子樹遞歸查找
            if(this.right == null) {
                return null;
            }
            return this.right. search(value);
        }
    }

    public Node searchParent(int value){

        //若是當前節點是須要刪除節點的父節點則返回
        if((this.left!=null && this.left.value == value) ||
                (this.right!=null && this.right.value == value)){
            return this;
        }else{
            //若是查找的值小於當前節點的值,而且當前節點的左子節點不爲空
            if(value <this.value && this.left!=null){
                return this.left.searchParent(value);
            }else if(value >= this.value && this.right!=null){
                //若是查找的值大於等於於當前節點的值,而且當前節點的右子節點不爲空
                return  this.right.searchParent(value);
            }else {
                return null;//沒有找到父節點,好比說節點7
            }
        }

    }

    //添加節點方法
    //遞歸方式添加節點,要知足二叉排序樹的要求
    //要求是:`左子節點的值比當前節點的值小,右子節點的值比當前節點的值大。`
    public void add(Node node) {

        if (node == null) {
            return;
        }

        //判斷傳入的節點的值,和當前節點值的關係

        //添加的節點小於當前節點
        if (node.value < this.value) {
            if (this.left == null) {
                this.left = node;
            } else {
                this.left.add(node);
            }
        } else {//添加的節點大於當前節點
            if (this.right == null) {
                this.right = node;
            } else {
                this.right.add(node);
            }
        }
    }

    @Override
    public String toString() {
        return "Node{" +"value=" + value +'}';
    }

    //中序遍歷
    public void infixOrder(){
        if(this.left != null){
            this.left.infixOrder();
        }
        System.out.println(this);
        if(this.right != null){
            this.right.infixOrder();
        }
    }
}
class AVLTree {

    private Node root;

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }

    //添加節點的方法
    public  void add(Node node){
        if(root == null){
            root = node;
        }else{
            root.add(node);
        }
    }
    /**
     *  @param node 傳入的節點(當作新二叉排序樹的根節點)
     *  return 返回新跟節點的最小節點的值
     */
    public int delRigthTreeMin(Node node){

        Node target = node;

        //循環的查找左子節點,找到最小值
        while(target.left!=null) {
            target = target.left;
        }
        //刪除最小值
        delNode(target.value);
        //返回最小值
        return target.value;
    }


    public void delNode(int value){

        if(root == null){
            System.out.println("當前根節點爲空!沒法刪除節點!");
            return;
        }else{
            //1.須要先找到刪除的值的對應節點
            Node targetNode = search(value);

            //若是沒有找到須要刪除的節點
            if(targetNode == null){
                System.out.println("對不起!沒有找到刪除節點信息!");
                return;
            }

            //若是咱們發現根節點沒有左子節點與右子節點
            if(root.left == null && root.right == null){
                root = null;
                return;
            }

            //找到targetNode 的父節點
            Node  parent = searchParent(value);

            //若是刪除節點是葉子節點
            if(targetNode.left == null && targetNode.right == null){

                //判斷刪除節點是父節點的左子節點仍是右子節點
                if(parent.left!= null && parent.left.value == targetNode.value){
                    parent.left = null;
                }else if (parent.right!= null && parent.right.value == targetNode.value){
                    parent.right = null;
                }
            }else if (targetNode.left != null && targetNode.right != null){

                int minValue = delRigthTreeMin(targetNode.right);
                targetNode.value = minValue;//重置值

            }else{//刪除只有一顆子樹的節點

                //若是刪除節點的子節點是左子節點
                if(targetNode.left !=null){
                    if(parent!=null){
                        //判斷刪除節點是父節點的左子節點仍是右子節點
                        if(parent.left.value == targetNode.value){
                            //將原刪除節點的位置給到子節點
                            parent.left = targetNode.left;
                        }else if (parent.right.value == targetNode.value){
                            //將原刪除節點的位置給到子節點
                            parent.right = targetNode.left;
                        }
                    }else{
                        root = targetNode.left;
                    }
                }else if (targetNode.right != null){ //若是刪除節點的子節點是右子節點

                    if(parent!=null){
                        //判斷刪除節點是父節點的左子節點仍是右子節點
                        if( parent.left.value == targetNode.value){
                            //將原刪除節點的位置給到子節點
                            parent.left = targetNode.right;
                        }else if (parent.right.value == targetNode.value){
                            //將原刪除節點的位置給到子節點
                            parent.right = targetNode.right;
                        }
                    }else{
                        root = targetNode.right;
                    }
                }
            }

        }
    }

    //查找須要刪除節點的方法
    public Node search(int value){

        if(root == null){
            return null;
        }else{
            return root.search(value);
        }
    }
    //查找須要刪除節點的父節點信息
    public Node searchParent(int value){
        if(root == null){
            return null;
        }else{
            return root.searchParent(value);
        }
    }


    //調用中序遍歷的方法
    public void infixOrder(){
        if(root == null){
            System.out.println("當前二叉排序根節點爲空,沒法遍歷");
            return;
        }else{
            root.infixOrder();
        }
    }
}

image.png

如上圖所示,咱們取的該這顆樹的高度是爲:3 ,算上根節點則是 4

因此咱們求該樹的高度,須要知道左節點與右節點的高度分別是多少

class Node{
    
    //......省略其餘關鍵代碼   
    
    //返回當前節點的左子樹的高度
    public int leftHigth(){
        if(left == null){
            return 0;
     }
        return left.hight();
    }
    
    //返回當前節點的右子樹的高度
    public int rightHight(){
        if(right == null){
            return 0;
     }
        return right.hight();
    }
    
    //返回當前節點的高度,若算上根節點則須要 + 1 
    public int hight(){
        return Math.max(left == null? 0 : left.hight(),right == null?0:right.hight()) + 1;
    }
     
}

有沒有發現,咱們須要知道左子樹的高度是多少

同時也須要知道左子樹的左子樹與右邊子樹是多少.....

這是一個一直遞歸的過程。

public static void main(String[] args) {

    int[] arr ={4,3,6,5,7,8};

    AVLTree avlTree = new AVLTree();
    for(int i = 0; i<arr.length; i++){
        avlTree.add(new Node(arr[i]));
    }

    //遍歷
    System.out.println("中序遍歷");
    avlTree.infixOrder();


    //節點高度
    System.out.println("算上跟節點高度爲:"+avlTree.getRoot().hight());
}

運行結果以下:
中序遍歷
Node{value=3}
Node{value=4}
Node{value=5}
Node{value=6}
Node{value=7}
Node{value=8}
算上跟節點高度爲:4

咱們剛剛也說了,算上跟根節點高度就是4,那麼咱們看看左子樹和右子樹

//節點高度
System.out.println("節點高度爲:"+avlTree.getRoot().hight());
//節點高度
System.out.println("左節點高度爲:"+avlTree.getRoot().leftHigth());
//節點高度
System.out.println("右節點高度爲:"+avlTree.getRoot().rightHight());

運行結果以下:
節點高度爲:4
左節點高度爲:1
右節點高度爲:3

咱們剛剛說到,左右兩個子樹的高度差絕對超過1纔去進行平衡調整,那麼當前的狀況則須要進行調整:右旋轉

class Node{
    
    //......省略其餘關鍵代碼 
    //RR旋轉方法
    private void RightRotate(){

        //建立一個新節點newNode等於當前根節點root,值相等
        Node newNode = new Node(value);

        //新節點newNode的左子樹設置爲當前根節點root的左子樹
        newNode.left = left;

        //新節點newNode的右子樹設置爲當前根節點root的右子樹的左子樹
        newNode.right = right.left;

        //當前根節點root的值換爲右子節點的值
        value = right.value;

        //當前根節點root的右子樹設置成根節點root的右子樹的右子樹
        right = right.right;

        //當前根節點root的左子樹設置爲新節點
        left = newNode;
    }
    
    //優化添加節點操做
    public void add(Node node) {

        if (node == null) {
            return;
        }

        //判斷傳入的節點的值,和當前節點值的關係

        //添加的節點小於當前節點
        if (node.value < this.value) {
            if (this.left == null) {
                this.left = node;
            } else {
                this.left.add(node);
            }
        } else {//添加的節點大於當前節點
            if (this.right == null) {
                this.right = node;
            } else {
                this.right.add(node);
            }
        }

        //當添加完一個節點後:若是(右子樹的高度 - 左子樹的高度)> 1 則執行RR旋轉
        if(rightHight() - leftHigth() > 1 ){
            RightRotate();//執行RR旋轉
        }
    }
}

接下來咱們實踐看看,當添加節點知足條件是否會進行平衡調整

public static void main(String[] args) {

        int[] arr ={4,3,6,5,7,8};

        AVLTree avlTree = new AVLTree();
        for(int i = 0; i<arr.length; i++){
            avlTree.add(new Node(arr[i]));
        }

        //遍歷
        System.out.println("中序遍歷");
        avlTree.infixOrder();


        //節點高度
        System.out.println("節點高度爲:"+avlTree.getRoot().hight());
        //節點高度
        System.out.println("左節點高度爲:"+avlTree.getRoot().leftHigth());
        //節點高度
        System.out.println("右節點高度爲:"+avlTree.getRoot().rightHight());
}

運行結果以下:
中序遍歷
Node{value=3}
Node{value=4}
Node{value=5}
Node{value=6}
Node{value=7}
Node{value=8}
節點高度爲:3
左節點高度爲:2
右節點高度爲:2

這時咱們進行平衡調整,從左右兩個子樹的高度差沒有超過1了。

3、經過示例認識平衡二叉樹的左旋轉

給你一個數列{10,12,8,9,7,6},讓你可以高效的完成對數據的查詢和添加

那麼按照咱們以前的思路,先構建:一顆二叉排序樹

二叉排序樹的特色?

非葉子節點特色:左子節點的值比當前節點的值小,右子節點的值比當前節點的值大。
特別說明:若是有相同的值,能夠將該節點放在左子節點或右子節點

回顧構建二叉排序樹思路分析

  • 判斷左子節點的值是否比當前節點的值小
  • 不然判斷右子節點的值比當前節點的值大
  • 遞歸判斷是否符合左子節點、右子節點的條件

image.png

咱們發現這顆二叉排序樹左子樹高度爲3,右邊子樹高度爲1

此時不符合平衡二叉樹的特色:它是一顆空樹或它的左右兩個子樹的高度差絕對超過1

根據上面介紹的四種平衡調整模式介紹,目前比較符合的是LL旋轉

image.png

根據咱們前面的示例經驗,咱們能夠直接進行實現思路分析

  • 建立一個新節點newNode等於當前根節點root,值相等

image.png

  • 新節點newNode的右子樹設置爲當前根節點root的右子樹

image.png

  • 新節點newNode的左子樹設置爲當前根節點root的左子樹的右子樹

image.png

  • 當前根節點root的值換爲左子節點的值

image.png

  • 當前根節點root的左子樹設置成根節點root的左子樹的左子樹

image.png

  • 當前根節點root的右子樹設置爲新節點

image.png

示例代碼實現

class Node{
    
    //......省略其餘關鍵代碼   
    
    //LL旋轉方法
    private void leftRotate(){

        //建立一個新節點newNode等於當前根節點root,值相等
        Node newNode = new Node(value);
        //新節點newNode的右子樹設置爲當前根節點root的右子樹
        newNode.right = right;
        //新節點newNode的`左子樹`設置爲當前根節點root的`左子樹的右子樹`
        newNode.left = left.right;
        //當前根節點root的值換爲左子節點的值
        value = left.value;
        //當前根節點root的左子樹設置成根節點root的`左子樹的左子樹`
        left = left.left;
        //當前根節點root的右子樹設置爲新節點
        right = newNode; 
    }
    
    //優化添加節點操做
    public void add(Node node) {

        if (node == null) {
            return;
        }

        //判斷傳入的節點的值,和當前節點值的關係

        //添加的節點小於當前節點
        if (node.value < this.value) {
            if (this.left == null) {
                this.left = node;
            } else {
                this.left.add(node);
            }
        } else {//添加的節點大於當前節點
            if (this.right == null) {
                this.right = node;
            } else {
                this.right.add(node);
            }
        }

        //當添加完一個節點後:若是(右子樹的高度 - 左子樹的高度)> 1 則執行RR旋轉
        if(rightHight() - leftHigth() > 1 ){
            RightRotate();//執行RR旋轉
        }
        //當添加完一個節點後:若是(左子樹的高度 - 右子樹的高度)> 1 則執行LL旋轉
        if(leftHigth() - rightHight() > 1 ){
            leftRotate();//執行LL旋轉
        }
    }
}

接下來咱們Demo測試一下爲調整以前的高度分別是多少

public static void main(String[] args) {

    //int[] arr ={4,3,6,5,7,8};

    int[] arr ={10,12,8,9,7,6};

    AVLTree avlTree = new AVLTree();
    for(int i = 0; i<arr.length; i++){
        avlTree.add(new Node(arr[i]));
    }

    //遍歷
    System.out.println("中序遍歷");
    avlTree.infixOrder();

    //節點高度
    System.out.println("節點高度爲:"+avlTree.getRoot().hight());
    //節點高度
    System.out.println("左節點高度爲:"+avlTree.getRoot().leftHigth());
    //節點高度
    System.out.println("右節點高度爲:"+avlTree.getRoot().rightHight());
}

運行結果以下:
中序遍歷
Node{value=6}
Node{value=7}
Node{value=10}
Node{value=9}
Node{value=8}
Node{value=12}
節點高度爲:3
左節點高度爲:2
右節點高度爲:2

這時咱們進行平衡調整,從左右兩個子樹的高度差沒有超過1了。

4、經過示例認識平衡二叉樹的雙旋轉

給你一個數列{10,11,7,6,8,9},讓你可以高效的完成對數據的查詢和添加

那麼按照咱們以前的思路,先構建:一顆二叉排序樹

image.png

咱們發現這顆二叉排序樹左子樹高度爲3,右邊子樹高度爲1

此時不符合平衡二叉樹的特色:它是一顆空樹或它的左右兩個子樹的高度差絕對超過1

按照咱們以前思路適合的是LL旋轉,那麼咱們執行左旋後的樣子發現是

image.png

那麼出現這種問題的緣由是什麼呢?
分析1:加入節點九時,左子樹(節點7)的樹高度 > 右子樹(節點11) 的高度
分析2:左子樹高度 - 右子樹高度 >1 觸發LL旋轉,就變成上面那樣了

image.png
那麼咱們能夠根據上面的LR介紹能夠猜到一些思路,解決這個問題.

咱們在符合:執行LL旋轉時條件時
思路1.獲取左子樹的右子樹(節點8)高度,取名爲:k
思路2.獲取左子樹(節點7)的高度,取名爲:J
思路3.若是 k > J,對左子樹進行RR旋轉
思路4.若是 k < J,直接進行LL旋轉

簡單的一句話:若是K>J,則先旋轉子樹再旋轉本身
image.png
image.png

同時咱們在符合:執行RR旋轉時條件時
思路1.獲取右子樹的左子樹高度 ,取名爲:U
思路2.獲取右子樹(節點11)的高度,取名爲:L
思路3.若是U > L,對右子樹進行LL旋轉
思路4.若是U < L,直接進行RR旋轉

class Node{
    
    //......省略其餘關鍵代碼   
    
    //優化添加節點操做
    public void add(Node node) {

        if (node == null) {
            return;
        }

        //判斷傳入的節點的值,和當前節點值的關係
        //添加的節點小於當前節點
        if (node.value < this.value) {
            if (this.left == null) {
                this.left = node;
            } else {
                this.left.add(node);
            }
        } else {//添加的節點大於當前節點
            if (this.right == null) {
                this.right = node;
            } else {
                this.right.add(node);
            }
        }
        //當添加完一個節點後:若是(右子樹的高度 - 左子樹的高度)> 1 則執行RR旋轉
        if(rightHight() - leftHigth() > 1 ){
            //獲取它的右子樹的左子樹的高度 取名U,獲取它的右子樹高度L
            //若是u > l 執行LL旋轉
            if(right != null && right.leftHigth()> right.rightHight()){
                right.leftRotate();//執行LL旋轉
                RightRotate();//執行RR旋轉
            }else{
                RightRotate();
            }
            return;//防止接着往下走
        }
        //當添加完一個節點後:若是(左子樹的高度 - 右子樹的高度)> 1 則執行LL旋轉
        if(leftHigth() - rightHight() > 1 ){
            //獲取左子樹的右子樹高度,取名爲:k 獲取左子樹的高度,取名爲:J
            //若是 k > J,對左子樹進行RR旋轉
            if(left != null && left.rightHight() > left.leftHigth()){
                left.RightRotate();//執行RR旋轉
                leftRotate();//執行LL旋轉
            }else{
                leftRotate();//執行LL旋轉
            }
        }
    
    }
}

接下來讓咱們使用Demo驗證一下咱們的思路

public static void main(String[] args) {

    //int[] arr ={4,3,6,5,7,8};

    int[] arr ={10,12,8,9,7,6};

    AVLTree avlTree = new AVLTree();
    for(int i = 0; i<arr.length; i++){
        avlTree.add(new Node(arr[i]));
    }

    //遍歷
    System.out.println("中序遍歷");
    avlTree.infixOrder();

    //節點高度
    System.out.println("節點高度爲:"+avlTree.getRoot().hight());
    //節點高度
    System.out.println("左節點高度爲:"+avlTree.getRoot().leftHigth());
    //節點高度
    System.out.println("右節點高度爲:"+avlTree.getRoot().rightHight());
    System.out.println("右節點高度爲:"+avlTree.getRoot().rightHight());
    System.out.println("當前根節點爲:"+avlTree.getRoot());
    System.out.println("當前根節點的左節點爲:"+avlTree.getRoot().left);
    System.out.println("當前根節點的右節點爲:"+avlTree.getRoot().right);
}

運行結果以下:
中序遍歷
Node{value=6}
Node{value=7}
Node{value=8}
Node{value=9}
Node{value=10}
Node{value=11}
節點高度爲:3
左節點高度爲:2
右節點高度爲:2
當前根節點爲:Node{value=8}
當前根節點的左節點爲:Node{value=7}
當前根節點的右節點爲:Node{value=10}
相關文章
相關標籤/搜索