1. 定義:帶有平衡條件的二叉搜索樹。平衡條件為其每個(gè)節(jié)點(diǎn)的左子樹和右子樹的高度最多差1。該平衡條件保證了樹的深度為O(log N).
2. 具體實(shí)現(xiàn)過程:
a. AVL樹節(jié)點(diǎn)的定義:
聲明了節(jié)點(diǎn)值,左右孩子節(jié)點(diǎn)和節(jié)點(diǎn)高度
/**
* 定義AVL樹的節(jié)點(diǎn)
* @param <T>
*/
private class AVLTreeNode<T extends Comparable<T>>{
T key;//節(jié)點(diǎn)值
int height;//節(jié)點(diǎn)高度
AVLTreeNode<T> left;
AVLTreeNode<T> right;
public AVLTreeNode(T key, AVLTreeNode<T> left, AVLTreeNode<T> right){
this.key = key;
this.left = left;
this.right = right;
this.height = 0;
}
}
b. AVL樹中節(jié)點(diǎn)的查找:
先比較節(jié)點(diǎn)值與傳入的值,再遞歸查找左右子樹
/**
* 根據(jù)傳入的值和樹,實(shí)現(xiàn)在樹中查找是否存在某個(gè)節(jié)點(diǎn)值為key
* @param x
* @param key
* @return
*/
private AVLTreeNode<T> search(AVLTreeNode<T> x, T key){
if (x == null){
return null;
}
//進(jìn)行比較
int cmp = key.compareTo(x.key);
//查找左子樹
if (cmp < 0){
return search(x.left, key);
}
//查找右子樹
else if (cmp > 0){
return search(x.right, key);
}
//查找成功,返回
else {
return x;
}
}
public AVLTreeNode<T> search(T key){
return search(root, key);
}
非遞歸版查找
private AVLTreeNode<T> iterativeSearch(AVLTreeNode<T> x, T key){
while (x != null){
int cmp = key.compareTo(x.key);
if (cmp < 0){
x = x.left;
} else if (cmp > 0){
x = x.right;
} else {
return x;
}
}
return x;
}
public AVLTreeNode<T> iterativeSearch(T key){
return iterativeSearch(root, key);
}
3. 查找AVL樹中的最值:
最大值:不斷向右子樹查找,直到某個(gè)節(jié)點(diǎn)的右孩子節(jié)點(diǎn)為空,則返回當(dāng)前節(jié)點(diǎn)
private AVLTreeNode<T> maximum(AVLTreeNode<T> tree){
if (tree == null){
return null;
}
while (tree.right != null){
tree = tree.right;
}
return tree;
}
public T maximum(){
AVLTreeNode<T> p = maximum(root);
if (p != null){
return p.key;
}
return null;
}
最小值:不斷向左子樹查找,直到某個(gè)節(jié)點(diǎn)的左孩子節(jié)點(diǎn)為空,則返回當(dāng)前結(jié)點(diǎn)
public T minimum(){
AVLTreeNode<T> p = minimum(root);
if (p != null){
return p.key;
}
return null;
}
private AVLTreeNode<T> minimum(AVLTreeNode<T> tree){
if (tree == null){
return null;
}
while (tree.left != null){
tree = tree.left;
}
return tree;
}
4. 對(duì)AVL樹進(jìn)行插入節(jié)點(diǎn):
當(dāng)我們進(jìn)行插入操作時(shí),若不會(huì)破壞AVL樹平衡的特性,則直接插入即可,否則在插入完成之前我們要進(jìn)行一些簡(jiǎn)單的修正,我們稱其為旋轉(zhuǎn)。
出現(xiàn)不平衡的四種情況,我們假定出現(xiàn)不平衡的節(jié)點(diǎn)為a.
1. 對(duì) a 的左兒子的左子樹進(jìn)行一次插入
2. 對(duì) a 的左兒子的右子樹進(jìn)行一次插入
3. 對(duì) a 的右兒子的右子樹進(jìn)行一次插入
4. 對(duì) a 的右兒子的左子樹進(jìn)行一次插入
其中情況1和情況3,我們通過對(duì)樹的一次單旋轉(zhuǎn)即可完成,而對(duì)于情況2和情況4,我們需要通過雙旋轉(zhuǎn)完成。
單旋轉(zhuǎn):
LL的旋轉(zhuǎn),即情況1:
single_rotation
/**
* 傳入不平衡的節(jié)點(diǎn),進(jìn)行LL旋轉(zhuǎn),返回平衡后的節(jié)點(diǎn)
* @param k2
* @return
*/
private AVLTreeNode<T> leftLeftRotation(AVLTreeNode<T> k2){
AVLTreeNode<T> k1;
//進(jìn)行旋轉(zhuǎn)
k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
//更新節(jié)點(diǎn)的高度
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
k1.height = Math.max(height(k1.left), k2.height) + 1;
return k1;
}
RR旋轉(zhuǎn),即情況3:
RR_rotation
/**
* 實(shí)現(xiàn)RR旋轉(zhuǎn)
* @param k1
* @return
*/
private AVLTreeNode<T> rightRightRotation(AVLTreeNode<T> k1){
AVLTreeNode<T> k2;
//進(jìn)行旋轉(zhuǎn)
k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
//更新高度
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k2.right),k1.height) + 1;
return k2;
}
雙旋轉(zhuǎn):
LR旋轉(zhuǎn),即情況2
LR_Rotation
/**
* 實(shí)現(xiàn)LR旋轉(zhuǎn)
* @param k3
* @return
*/
private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> k3){
//獲取到k1節(jié)點(diǎn)
AVLTreeNode<T> k1 = k3.left;
//對(duì)k1進(jìn)行RR旋轉(zhuǎn)
k3.left = rightRightRotation(k1);
//再對(duì)k3進(jìn)行LL旋轉(zhuǎn)
return leftLeftRotation(k3);
}
RL旋轉(zhuǎn),即情況4:
RL_Rotation
/**
* 實(shí)現(xiàn)RL旋轉(zhuǎn)
* @param k1
* @return
*/
private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> k1){
//獲取到k3節(jié)點(diǎn)
AVLTreeNode<T> k3 = k1.right;
//對(duì)k3節(jié)點(diǎn)進(jìn)行LL旋轉(zhuǎn)
k1.right = leftLeftRotation(k3);
//對(duì)k1節(jié)點(diǎn)進(jìn)行RR旋轉(zhuǎn)
return rightRightRotation(k1);
}
實(shí)現(xiàn)插入節(jié)點(diǎn)操作:
/**
* 實(shí)現(xiàn)插入節(jié)點(diǎn)的操作
* @param tree
* @param key
* @return
*/
private AVLTreeNode<T> insert(AVLTreeNode<T> tree, T key){
//若當(dāng)前結(jié)點(diǎn)為空,則創(chuàng)建一個(gè)新節(jié)點(diǎn),并返回
if (tree == null){
return new AVLTreeNode<T>(key, null, null);
}
//進(jìn)行比較
int cmp = key.compareTo(tree.key);
//進(jìn)入左子樹
if (cmp < 0){
//對(duì)左子樹進(jìn)行遞歸插入
tree.left = insert(tree.left, key);
//若插入后,存在不平衡情況
if (height(tree.left) - height(tree.right) == 2){
//若插入的位置為左邊,則進(jìn)行LL旋轉(zhuǎn)
if (key.compareTo(tree.left.key) < 0){
tree = leftLeftRotation(tree);
}
//若插入的位置在右邊,則進(jìn)行LR旋轉(zhuǎn)
else {
tree = leftRightRotation(tree);
}
}
}
//進(jìn)入右子樹
else if (cmp > 0){
//對(duì)右子樹進(jìn)行遞歸插入
tree.right = insert(tree.right, key);
//若插入后,存在不平衡的情況
if (height(tree.right) - height(tree.left) == 2){
//若插入的位置在右邊,則進(jìn)行RR旋轉(zhuǎn)
if (key.compareTo(tree.right.key) > 0){
tree = rightRightRotation(tree);
}
//若插入的位置在左邊,則進(jìn)行RL旋轉(zhuǎn)
else {
tree = rightLeftRotation(tree);
}
}
}
//存在該節(jié)點(diǎn)了,不做操作
else {
System.out.println("添加失敗:不允許添加相同的節(jié)點(diǎn)");
}
//更新節(jié)點(diǎn)的高度
tree.height = Math.max(height(tree.left), height(tree.right)) + 1;
return tree;
}
public void insert(T key){
root = insert(root, key);
}
實(shí)現(xiàn)刪除節(jié)點(diǎn)操作:
/**
* 實(shí)現(xiàn)刪除節(jié)點(diǎn)操作,并返回刪除的節(jié)點(diǎn)
* @param tree
* @param delete
* @return
*/
private AVLTreeNode<T> remove(AVLTreeNode<T> tree, AVLTreeNode<T> delete){
//沒有刪除的節(jié)點(diǎn),直接返回空
if (tree == null || delete == null){
return null;
}
//進(jìn)行比較
int cmp = delete.key.compareTo(tree.key);
//進(jìn)入左子樹
if (cmp < 0){
//對(duì)左邊進(jìn)行遞歸刪除
tree.left = remove(tree.left, delete);
//存在不平衡的情況
if (height(tree.right) - height(tree.left) == 2){
//因?yàn)閯h除的是左子樹節(jié)點(diǎn),則要調(diào)整的為右子樹節(jié)點(diǎn)
AVLTreeNode<T> r =tree.right;
//左大于右,則進(jìn)行RL旋轉(zhuǎn)
if (height(r.left) > height(r.right)){
tree = rightLeftRotation(tree);
}
//右高于左,則進(jìn)行RR旋轉(zhuǎn)
else {
tree = rightRightRotation(tree);
}
}
}
//進(jìn)入右子樹
else if (cmp > 0){
//進(jìn)行遞歸刪除
tree.right = remove(tree.right, delete);
//出現(xiàn)不平衡的情況
if (height(tree.left) - height(tree.right) == 2){
//刪除的是右子樹節(jié)點(diǎn),因此要調(diào)整的是左子樹
AVLTreeNode<T> l = tree.left;
//右高于左,則進(jìn)行LR旋轉(zhuǎn)
if (height(tree.right) > height(tree.left)){
tree = leftRightRotation(tree);
}
//左高于右,則進(jìn)行LL旋轉(zhuǎn)
else {
tree = leftLeftRotation(tree);
}
}
}
//進(jìn)行刪除當(dāng)前結(jié)點(diǎn)
else {
//左右孩子都不為空
if ((tree.left != null) && (tree.right != null)){
//左高于右,那么要調(diào)整的是左子樹
if (height(tree.left) > height(tree.right)){
//獲取到左子樹的最大節(jié)點(diǎn),因?yàn)榇斯?jié)點(diǎn)不含孩子
AVLTreeNode<T> max = maximum(tree.left);
//左子樹最大節(jié)點(diǎn)替換當(dāng)前結(jié)點(diǎn)
tree.key = max.key;
//刪除左子樹的最大節(jié)點(diǎn)
tree.left = remove(tree.left,max);
} else {
//獲取右子樹的最小節(jié)點(diǎn)
AVLTreeNode<T> min = minimum(tree.right);
//用右子樹的最小節(jié)點(diǎn)替換當(dāng)前結(jié)點(diǎn)
tree.key = min.key;
//刪除右子樹的最小節(jié)點(diǎn)
tree.right = remove(tree.right, min);
}
}
//若只存在左孩子或右孩子,則使孩子替換當(dāng)前結(jié)點(diǎn)
else {
tree = (tree.left != null) ? tree.left : tree.right;
}
}
return tree;
}
public void remove(T key){
AVLTreeNode<T> z = search(root, key);
if (z != null){
root = remove(root, z);
}
}