GBU610-ASEMI智慧家居整流橋GBU610
一:AVL樹的概念
概念:
平衡二叉樹也叫二叉搜尋樹又被稱為AVL樹,可以保證查詢效率較高。它是一棵空樹或者它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。平衡二叉樹的實現方法有紅黑樹、AVL、替罪羊樹、Treap、伸展樹等。
二:AVL樹左旋轉思路
當右子樹的高度比左子樹高度大1時,進行左旋轉。
首先假定一棵二叉樹 [4,3,6,5,7,8]
第一步:建立一個新的節點,值為當前根節點的值 【4】
第二步:將新節點【4】的左子樹設定為當前節點【根節點】的左子樹
第三步:把新節點【4】的右子樹設定為當前節點【根節點】的右子樹的左子樹
第四步:將當前節點【根節點】的值變為右子節點【6】的值
第五步:把當前節點【根節點】的右子樹設定為右子樹的右子樹
第六步:將當前節點的左子樹設定為新節點
最終節點【6】被當作垃圾回收
在實現程式碼之前,我們需要知道的一個核心的操作:
我們需要知道左右子樹的高度是多少,因為只有當左右子樹的高度差大於1才需要進行旋轉。
計算高度程式碼實現:
//返回左子樹的高度 public int leftHeight(){ if(left == null){ return 0; } return left.height(); } //返回右子樹的高度 public int rightHeight(){ if(right == null){ return 0; } return right.height(); } //返回以當前節點為根節點的高度 public int height(){ return Math.max(left == null ? 0: left.height(), right == null ? 0: right.height())+1; }
左旋轉方法程式碼
private void leftRotate(){ //1.建立新的節點,值為根節點的值 Node newnode = new Node(value); //2.將新節點的左子樹設定為當前節點的左子樹 newnode.left = this.left; //3.將新節點的右子樹設定為當前節點右子樹的左子樹 newnode.right = this.right.left; //4.將當前節點的值設定為右子節點的值 this.value = this.right.value; //5.將當前節點的右子樹設定為右子樹的右子樹 this.right = this.right.right; //6.將當前節點的左子樹設定為新節點 this.left = newnode; }
三:AVL樹右旋轉思路
當左子樹的高度比右子樹的高度大1時,需要進行右旋轉。
首先假定一棵二叉樹 [10,12,8,9,7,6]
第一步:建立一個新的節點,值為當前根節點的值【10】
第二步:將新節點【10】的右子樹設定為當前節點的右子樹【12】
第三步:將新節點【10】的左子樹設定為當前節點的左子樹的右子樹【9】
第四步:將當前節點【10】的值設定為左子節點【8】的值
第五步:將當前節點【8】的左子樹設定為左子樹的左子樹【7】
第六步:將當前節點【8】的右子樹設定為新節點【10】
最後:節點【8】被當作垃圾回收
同樣我們需要計算出左右子樹的高度,程式碼與左旋轉一樣。
右旋轉方法程式碼:
private void rightRotate(){
//1.建立一個新的節點,值為當前根節點的值
Node newNode = new Node(value);
//2.將新節點的右子樹設定為當前節點的右子樹
newNode.right = this.right;
//3.將新節點的左子樹設定為當前節點的左子樹的右子樹
newNode.left = this.left.right;
//4.將當前節點的值設定為左子節點的值
this.value = this.left.value;
//5.將當前節點的左子樹設定為左子樹的左子樹
this.left = this.left.left;
//6.將當前節點的右子樹設定為新節點
this.right = newNode;
}
在上述兩個數列中單旋轉就可以將非平衡二叉樹轉成平衡二叉樹,但是左/右旋轉在某些情況下不能將非平衡樹轉成平衡樹。比如:【10,11,7,6,8,9】那麼這個時候就需要採用雙旋轉了。
四:AVL樹雙旋轉思路
假定一棵二叉樹 [10,11,7,6,8,9]
問題分析:
1.當前節點【10】的左子樹的右子樹的高度大於它的左子樹的高度
解決方法:
1.首先對當前節點【10】的左子樹進行左旋轉
2.再對當前節點【10】進行右旋轉即可
程式碼實現:
//新增完一個節點以後,如果(左子樹的高度 - 右子樹的高度) > 1,右旋轉
if(leftHeight() - rightHeight() > 1){
//判斷它的左子樹的右子樹高度是否比左子樹高
if(left.rightHeight() > left.leftHeight()){
//對當前結點的左子樹進行左旋轉
left.leftRotate();
//再進行右旋轉
rightRotate();
}else{
//直接進行右旋轉
rightRotate();
}
return; //返回,防止進入下面的操作
}
同理,另一種情況(右子樹的左子樹高度大於右子樹的高度)
解決思路:
1.首先對當前節點的右子樹進行右旋轉
2.再對當前節點進行左旋轉
程式碼實現:
//新增完一個節點以後,如果(右子樹的高度 - 左子樹的高度) > 1,左旋轉
if(rightHeight() - leftHeight() > 1){
//判斷它的右子樹的左子樹高度是否比右子樹高
if(right.leftHeight() > right.rightHeight()){
//對當前結點的右子樹進行右旋轉
right.rightRotate();
//再進行左旋轉
leftRotate();
}else{
//直接進行左旋轉
leftRotate();
}
return;
}