文字介绍和图片来自http://www.cnblogs.com/skywang12345/p/3577479.html
1.AVL介绍
AVL树是高度平衡的而二叉树。它的特点是:AVL树中任何节点的两个子树的高度最大差别为1。
2.AVL的实现
2.1 结点定义
//结点定义
private class AVLNode {
Key key;
Value val;
int h;
AVLNode left,right;
public AVLNode(Key k,Value v,int h) {
key = k; val = v; left = null; right = null; this.h = h;
}
}
2.2 旋转
如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。这种失去平衡的可以概括为4种姿态:LL(左左),LR(左右),RR(右右)和RL(右左)。下面给出它们的示意图:
上图中的4棵树都是”失去平衡的AVL树”,从左往右的情况依次是:LL、LR、RL、RR。除了上面的情况之外,还有其它的失去平衡的AVL树,如下图:
上面的两张图都是为了便于理解,而列举的关于”失去平衡的AVL树”的例子。总的来说,AVL树失去平衡时的情况一定是LL、LR、RL、RR这4种之一,它们都由各自的定义:
2.2.1 LL的旋转
LL失去平衡的情况,可以通过一次旋转让AVL树恢复平衡。如下图:
图中左边是旋转之前的树,右边是旋转之后的树。从中可以发现,旋转之后的树又变成了AVL树,而且该旋转只需要一次即可完成。
LL的旋转代码
/**
* LL:左左对应的情况(左单旋转),LL失去平衡的情况,可以通过一次旋转让AVL树恢复平衡。
* @param p
* @return 旋转后的根节点
*/
private AVLNode LLrotation(AVLNode p) {
AVLNode v = p.left;
p.left = v.right;
v.right = p;
p.h = Math.max(height(p.left), height(p.right))+1;
v.h = Math.max(height(v.left), height(v.right))+1;
return v;
}
2.2.2 RR的旋转
理解了LL之后,RR就相当容易理解了。RR是与LL对称的情况!RR恢复平衡的旋转方法如下:
图中左边是旋转之前的树,右边是旋转之后的树。RR旋转也只需要一次即可完成。
RR的旋转代码
/**
* RR:右右对应的情况(右单旋转)。
* @param p
* @return 旋转后的根节点
*/
private AVLNode RRrotation(AVLNode p) {
AVLNode v = p.right;
p.right = v.left;
v.left = p;
p.h = Math.max(height(p.left), height(p.right))+1;
v.h = Math.max(height(v.left), height(v.right))+1;
return v;
}
2.2.3 LR的旋转
LR失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡。如下图:
第一次旋转是围绕”k1”进行的”RR旋转”,第二次是围绕”k3”进行的”LL旋转”。
LR的旋转代码
/**
* LR失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡。先RR再LL
* @param p
* @return
*/
private AVLNode LRrotation(AVLNode g) {
AVLNode p = g.left;
g.left = RRrotation(p);
return LLrotation(g);
}
2.2.4 RL的旋转
RL是与LR的对称情况!RL恢复平衡的旋转方法如下:
第一次旋转是围绕”k3”进行的”LL旋转”,第二次是围绕”k1”进行的”RR旋转”。
RL的旋转代码
/**
* RL失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡。先LL再RR
* @param p
* @return
*/
private AVLNode RLrotation(AVLNode g) {
AVLNode p = g.right;
g.right = LLrotation(p);
return RRrotation(g);
}
2.2.5 LL,RR,LR,RL 调整rebalance方案
代码
/**
* 调整二叉树使之平衡
* @param p
* @return
*/
private AVLNode rebalance(AVLNode p) {
if(p == null) return null;
//判断以p为根节点的左右子树是否平衡
if(Math.abs(height(p.left)-height(p.right))<2)
return p;
if(height(p.left)>height(p.right)) {
//若AVL左子树失去平衡,则进行相应的调节
if(height(p.left.left) - height(p.right) == 1)
p = LLrotation(p);//LL
else
p = LRrotation(p);//LR
}
else {
//若AVL右子树失去平衡,则进行相应的调节
if(height(p.right.right) - height(p.left) == 1)
p = RRrotation(p);//RR
else
p = RLrotation(p);//RL
}
return p;
}
2.3 插入
//插入
public void insert(Key key,Value val) {
if(key == null) return;
if(val == null) delete(key);
root = insert(root,key,val);
}
private AVLNode insert(AVLNode p,Key key,Value val) {
if(p == null) { p = new AVLNode(key,val,1); return p;}
int cmp = key.compareTo(p.key);
if(cmp < 0)
p.left = insert(p.left,key,val);
else if(cmp > 0)
p.right = insert(p.right,key,val);
else {
p.val = val; return p;
}
p.h = Math.max(height(p.left), height(p.right)) + 1;
p = rebalance(p);
return p;
}
2.4 删除
//删除
public void delete(Key key) {
root = delete(root,key);
}
private AVLNode delete(AVLNode p,Key key) {
if(p == null || key == null) return null;
int cmp = key.compareTo(p.key);
if(cmp < 0)
p.left = delete(p.left,key);
else if(cmp > 0)
p.right = delete(p.right,key);
else {
//删除
if(p.right == null) {
p = p.left;
}
else {
//选择右子树最小结点替换待删除结点
AVLNode rmin = min(p.right);
p.key = rmin.key; p.val = rmin.val;
p.right = delete(p.right,rmin.key);
}
}
if(p != null) {
p.h = Math.max(height(p.left), height(p.right)) + 1;
p = rebalance(p);
}
return p;
}
3 完整代码
package xwq.dt;
public class AVLTree<Key extends Comparable<Key>,Value> {
private AVLNode root;
//结点定义
private class AVLNode {
Key key;
Value val;
int h;
AVLNode left,right;
public AVLNode(Key k,Value v,int h) {
key = k; val = v; left = null; right = null; this.h = h;
}
}
public AVLTree() {
root = null;
}
//查找
public Value find(Key k) {
AVLNode result = find(root,k);
if(result != null) return result.val;
return null;
}
private AVLNode find(AVLNode p,Key k) {
if(k == null) return null;
while(p != null) {
int cmp = k.compareTo(p.key);
if(cmp<0) p = p.left;
else if(cmp>0) p = p.right;
else return p;
}
return null;
}
//插入
public void insert(Key key,Value val) {
if(key == null) return;
if(val == null) delete(key);
root = insert(root,key,val);
}
private AVLNode insert(AVLNode p,Key key,Value val) {
if(p == null) { p = new AVLNode(key,val,1); return p;}
int cmp = key.compareTo(p.key);
if(cmp < 0)
p.left = insert(p.left,key,val);
else if(cmp > 0)
p.right = insert(p.right,key,val);
else {
p.val = val; return p;
}
p.h = Math.max(height(p.left), height(p.right)) + 1;
p = rebalance(p);
return p;
}
//删除
public void delete(Key key) {
root = delete(root,key);
}
private AVLNode delete(AVLNode p,Key key) {
if(p == null || key == null) return null;
int cmp = key.compareTo(p.key);
if(cmp < 0)
p.left = delete(p.left,key);
else if(cmp > 0)
p.right = delete(p.right,key);
else {
//删除
if(p.right == null) {
p = p.left;
}
else {
//选择右子树最小结点替换待删除结点
AVLNode rmin = min(p.right);
p.key = rmin.key; p.val = rmin.val;
p.right = delete(p.right,rmin.key);
}
}
if(p != null) {
p.h = Math.max(height(p.left), height(p.right)) + 1;
p = rebalance(p);
}
return p;
}
/***************************************************************************
* AVL tree helper functions.
***************************************************************************/
/**
* 调整二叉树使之平衡
* @param p
* @return
*/
private AVLNode rebalance(AVLNode p) {
if(p == null) return null;
//判断以p为根节点的左右子树是否平衡
if(Math.abs(height(p.left)-height(p.right))<2)
return p;
if(height(p.left)>height(p.right)) {
//若AVL左子树失去平衡,则进行相应的调节
if(height(p.left.left) - height(p.right) == 1)
p = LLrotation(p);//LL
else
p = LRrotation(p);//LR
}
else {
//若AVL右子树失去平衡,则进行相应的调节
if(height(p.right.right) - height(p.left) == 1)
p = RRrotation(p);//RR
else
p = RLrotation(p);//RL
}
return p;
}
/**
* LL:左左对应的情况(左单旋转),LL失去平衡的情况,可以通过一次旋转让AVL树恢复平衡。
* @param p
* @return 旋转后的根节点
*/
private AVLNode LLrotation(AVLNode p) {
AVLNode v = p.left;
p.left = v.right;
v.right = p;
p.h = Math.max(height(p.left), height(p.right))+1;
v.h = Math.max(height(v.left), height(v.right))+1;
return v;
}
/**
* RR:右右对应的情况(右单旋转)。
* @param p
* @return 旋转后的根节点
*/
private AVLNode RRrotation(AVLNode p) {
AVLNode v = p.right;
p.right = v.left;
v.left = p;
p.h = Math.max(height(p.left), height(p.right))+1;
v.h = Math.max(height(v.left), height(v.right))+1;
return v;
}
/**
* LR失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡。先RR再LL
* @param p
* @return
*/
private AVLNode LRrotation(AVLNode g) {
AVLNode p = g.left;
g.left = RRrotation(p);
return LLrotation(g);
}
/**
* RL失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡。先LL再RR
* @param p
* @return
*/
private AVLNode RLrotation(AVLNode g) {
AVLNode p = g.right;
g.right = LLrotation(p);
return RRrotation(g);
}
/***************************************************************************
* Utility functions.
***************************************************************************/
public int height() {
return height(root);
}
private int height(AVLNode p) {
if(p==null) return 0;
return p.h;
}
public Key minKey() {
AVLNode min = min(root);
if(min == null) return null;
return min.key;
}
private AVLNode min(AVLNode p) {
if(p == null) return null;
while(p.left != null)
p = p.left;
return p;
}
public Key maxKey() {
AVLNode max = max(root);
if(max == null) return null;
return max.key;
}
private AVLNode max(AVLNode p) {
if(p==null) return null;
while(p.right != null)
p = p.right;
return p;
}
public boolean isBalance() {
return isBalance(root);
}
private boolean isBalance(AVLNode p) {
if(p == null) return true;
if(Math.abs(height(p.left)-height(p.right))>=2)
return false;
return isBalance(p.left) && isBalance(p.right);
}
/***************************************************************************
* AVL tree 遍历 functions.
***************************************************************************/
//前序遍历
public void preorder() {
System.out.println("preorder: ");
preorder(root);
System.out.println();
}
//中序遍历
public void inorder() {
System.out.println("inorder: ");
inorder(root);
System.out.println();
}
//后序遍历
public void postorder() {
System.out.println("postorder: ");
postorder(root);
System.out.println();
}
private void inorder(AVLNode p) {
if(p == null) return;
inorder(p.left);
System.out.print(p.key+" ");
inorder(p.right);
}
private void preorder(AVLNode p) {
if(p == null) return;
System.out.print(p.key+" ");
preorder(p.left);
preorder(p.right);
}
private void postorder(AVLNode p) {
if(p == null) return;
postorder(p.left);
postorder(p.right);
System.out.print(p.key+" ");
}
}