在上篇博客中已经提到平衡二叉树
平衡二叉树左子树和右子树 的高度差的绝对值不超过1的二叉排序树
定义节点:
public class AVLTreeNode {
private int value;//结点的数据
private int height;//树的高度
private AVLTreeNode left;//指向左孩子结点
private AVLTreeNode right;//指向左孩子结点
public AVLTreeNode(int value) {
this.value = value;
this.height = 0;
this.left = null;
this.right =null;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public AVLTreeNode getLeft() {
return left;
}
public void setLeft(AVLTreeNode left) {
this.left = left;
}
public AVLTreeNode getRight() {
return right;
}
public void setRight(AVLTreeNode right) {
this.right = right;
}
}
为平衡而生的旋转
1.LL旋转
左左单旋转时, 不满足AVL条件的最小树的根应该下移,该树的其他节点上移,而不管该树的左子树的右孩子或者存在或者不存在,在旋转过程中,都要把该左子树的的右孩子添加以作为最小树根的左孩子,因为即使不存在,添加null 也不影响最后的旋转效果
/**
* @Author ZHfei
* @Description //TODO LL左旋转,顺时针
* @Date 18:59 2020/6/7
**/
public AVLTreeNode singleRotateLeft(AVLTreeNode x){
AVLTreeNode w= x.getLeft();
x.setLeft(w.getRight());
w.setRight(x);
x.setHeight(Math.max(Height(x.getLeft()),Height(x.getRight()))+1);
w.setHeight(Math.max(Height(w.getLeft()),x.getHeight())+1);
return w;
}
/**
* @Author ZHfei
* @Description //TODO 求树的高度
* @Date 18:58 2020/6/7
**/
//求树的高度
public int Height(AVLTreeNode root) {
if (root == null) {
return -1;
}else {
return root.getHeight();
}
}
2.RR旋转
右右单旋转时, 不满足AVL条件的最小树的根应该下移,该树的其他节点上移,而不管该树的右子树的左孩子或者存在或不存在,在旋转过程中,都要把该右子树的左孩子添加以作为最小树根的右孩子,因为即使不存在,添加null 也不影响最后的 旋转效果
/**
* @Author ZHfei
* @Description //TODO RR右旋转,逆时针
* @Date 18:59 2020/6/7
**/
public AVLTreeNode singleRotateRight(AVLTreeNode w){
AVLTreeNode x= w.getRight();
w.setRight(x.getLeft());
x.setLeft(w);
w.setHeight(Math.max(Height(w.getRight()),Height(w.getLeft()))+1);
x.setHeight(Math.max(Height(x.getRight()),w.getHeight())+1);
return x;
}
3.LR旋转
/**
* @Author ZHfei
* @Description //TODO LR旋转
* @Date 19:00 2020/6/7
**/
public AVLTreeNode doubleRotateLeft(AVLTreeNode z){
z.setLeft(singleRotateRight(z.getLeft()));//在X和Y之间旋转
return singleRotateLeft(z);//在Z和Y之间旋转
}
4.RL旋转
/**
* @Author ZHfei
* @Description //TODO RL旋转
* @Date 19:01 2020/6/7
**/
public AVLTreeNode doubleRotateRight(AVLTreeNode x){
x.setRight(singleRotateRight(x.getLeft()));//在Z和Y之间旋转
return singleRotateRight(x);//在X和Y之间旋转
}
如何判断进行单旋转还是双旋转 (什么时候需要单旋转,而什么时候需要多旋转?)
1。高度不平衡需要α点的两棵子树高度差为2,故可得高度不平衡可能出现在下面四种情况中:
① 对α的左儿子的左子树进行一次插入。
② 对α的左儿子的右子树进行一次插入。
③ 对α的右儿子的左子树进行一次插入。
④ 对α的右儿子的右子树进行一次插入。
1.单旋转: 插入点不介于 不满足AVL条件的树根 和 树根对应孩子节点之间; (情形①、③ 即 左-左、右-右)
2.双旋转:插入点介于 不满足AVL条件的树根 和 树根对应孩子节点之间;(情形②、④ 即 左-右、右-左)
AVL的插入:
/**
* @Author ZHfei
* @Description //TODO 插入操作
* @Date 19:01 2020/6/7
**/
public AVLTreeNode insert(AVLTreeNode root, int data) {
if (root == null) {
root = new AVLTreeNode(data);//若原树为空, 生成并返回一个结点的AVL树
}else if (data < root.getValue()) {
root.setLeft(insert(root.getLeft(),data));
if (Height(root.getLeft())-Height(root.getRight()) == 2) {
if (data < root.getLeft().getValue()) {
root = singleRotateLeft(root);
}else {
root = doubleRotateLeft(root);
}
}
} else if (data > root.getValue()) {
root.setRight(insert(root.getRight(),data));
if (Height(root.getRight())-Height(root.getLeft()) == 2) {
if (data < root.getRight().getValue()) {
root = singleRotateRight(root);
} else {
root = doubleRotateRight(root);
}
}
}
/*否则,数据已经存在,程序什么也不做。*/
root.setHeight(Math.max(Height(root.getLeft()),Height(root.getRight()))+1);
return root;
}