本文基於二叉排序樹(BST)創作,若對二叉排序樹不瞭解建議先掌握二叉排序樹再學習文本
本文完整代碼下載
一、介紹
- 平衡二叉樹也叫平衡二叉搜索樹(Self-balancing binary search tree)又被稱爲AVL樹, 可以保證查詢效率較高。
- 具有以下特點:它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。平衡二叉樹的常用實現方法有紅黑樹、AVL、替罪羊樹、Treap、伸展樹等。
例:
二、二叉排序樹 問題分析
將數列{1,2,3,4,5,6} 創建爲一顆二叉排序樹(BST)
創建後的效果
問題
- 左子樹全部爲空,從形式上看,更像一個單鏈表。
- 插入速度沒有影響。
- 查詢速度明顯降低(因爲需要依次比較), 不能發揮BST的優勢,因爲每次還需要比較左子樹,其查詢速度比單鏈表還慢。
三、解決思路
AVL樹的基本操作一般涉及運做同在不平衡的二叉查找樹所運做的同樣的算法。但是要進行預先或隨後做一次或多次所謂的"AVL 旋轉"。
旋轉
左旋轉
右旋轉
雙旋轉
雙旋轉就是先進行左旋轉,再進行右旋轉或先進行右旋轉,在進行左旋轉
例
旋轉過後依然不符合條件
問題分析
在滿足右旋轉條件時,要判斷
(1)如果 是 左子樹的 右子樹高度 大於左子樹的左子樹時:
(2)就是 對 當前根節點的左子樹,先進行 左旋轉,
(3)然後, 在對當前根節點進行右旋轉即可。
否則,直接對當前節點(根節點)進行右旋轉.即可。
四、代碼實現
1.求樹的高度
class Node {
int value;
Node left;
Node right;
/**
* @return 以該節點爲根節點的樹的高度
*/
public int height() {
return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
}
/**
* @return 左子樹的高度
*/
public int leftHeight() {
if (left == null) {
return 0;
}
return left.height();
}
/**
* @return 右子樹的高度
*/
public int rightHeight() {
if (right == null) {
return 0;
}
return right.height();
}
}
2.左旋轉
class Node {
/**
* 左旋轉方法
*/
private void leftRotate() {
//創建新的結點,以當前根結點的值
Node newNode = new Node(value);
//把新的結點的左子樹設置成當前結點的左子樹
newNode.left = left;
//把新的結點的右子樹設置成當前結點右子樹的左子樹
newNode.right = right.left;
//把當前結點的值替換成右子結點的值
value = right.value;
//把當前節點的右子樹設置成當前節點右子樹的右子樹
right = right.right;
//把當前結點的左子樹(左子結點)設置成新的結點
left = newNode;
}
}
3.右旋轉
class Node {
/**
* 右旋轉
*/
private void rightRotate() {
Node newNode = new Node(value);
newNode.right = right;
newNode.left = left.right;
value = left.value;
left = left.left;
right = newNode;
}
}
4.添加結點
/**
* 添加結點
*
* @param 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,左旋轉
if (rightHeight() - leftHeight() > 1) {
//如果它的右子樹的左子樹的高度大於右子樹的右子樹的高度
if (right != null && right.leftHeight() > right.rightHeight()) {
//新對右子結點進行右旋轉
right.rightRotate();
//再對當前結點進行左旋轉
leftRotate();
} else {
//直接進行左旋轉
leftRotate();
}
return;
}
//當添加完成一個結點後,若(左子樹的高度-右子樹的高度)>1,右旋轉
//當添加完成一個結點後,若(右子樹的高度-左子樹的高度)>1,左旋轉
if (leftHeight() - rightHeight() > 1) {
//如果它的左子樹的右子樹的高度大於右子樹的左子樹的高度
if (left != null && left.rightHeight() > left.leftHeight()) {
//新對右子結點進行右旋轉
left.leftRotate();
//再對當前結點進行左旋轉
rightRotate();
} else {
//直接進行左旋轉
rightRotate();
}
}
}
本文完整代碼下載