AVL树
对于二叉搜索树而言,当存在单分支有序结构时,查找效率会非常差,此时AVL树可以有效解决这个问题
AVL树的插入
- 按照二叉搜索树的方式插入新节点
java
TreeNode node=new TreeNode(val);
if (root==null){
root=node;
return true;
}
TreeNode cur=root;
TreeNode parent=null;
while (cur!=null) {
if (cur.val < val) {
parent = cur;
cur = cur.right;
} else if (cur.val == val) {
return false;
} else {
parent = cur;
cur = cur.left;
}
}
if (parent.val<val){
parent.right=node;
}else{
parent.left=node;
}
node.parent=parent;
cur=node;
- 调整节点的平衡因子
java
//平衡因子的修改
while(parent!=null){
//先看cur是parent的左还是右 决定平衡因子是++还是--
if(cur==parent.right){
//如果是右树,那么右树高度增加 平衡因子++
parent.bf++;
}else {
//如果是左树,那么左树高度增加 平衡因子--
parent.bf--;
}
AVL树的旋转
java
//检查当前的平衡因子 是不是绝对值 1 0 -1
if (parent.bf==0){
//说明已经平衡了
break;
} else if (parent.bf == 1 || parent.bf == -1) {
//继续向上去修改平衡因子
cur=parent;
parent=cur.parent;
}else {
if (parent.bf==2){
//右树高-》需要降低右树的高度
if (cur.bf==1){
//左旋
rotateLeft(parent);
}else {
//cur.bf==-1(右左)
rotateRL(parent);
}
}else {
//parent.bf == -2 左树高-》需要降低左树的高度
if (cur.bf==-1){
//右旋
rotateRight(parent);
}else {
//cur.bf==1(左右)
rotateLR(parent);
}
}
//上述代码走完就平衡了
break;
}
}
- 新节点插入较高左子树的左侧---右单旋

java
private void rotateRight(TreeNode parent) {
TreeNode subL=parent.left;
TreeNode subLR=subL.right;
parent.left=subLR;
subL.right=parent;
//没有subLR
if(subLR!=null){
subLR.parent=parent;
}
//必须先记录
TreeNode Pparent=parent.parent;
parent.parent=subL;
//检查 当前是不是就是根节点
if (root==parent){
root=subL;
root.parent=null;
}else {
//不是根节点,判断这棵子树是左子树还是右子树
if (parent==Pparent.left){
Pparent.left=subL;
}else {
Pparent.right=subL;
}
subL.parent=Pparent;
}
subL.bf=0;
parent.bf=0;
}
2.新节点插入较高右子树的右侧---左单旋
'
java
private void rotateLeft(TreeNode parent) {
TreeNode subR=parent.right;
TreeNode subRL=subR.left;
parent.right=subRL;
subR.left=parent;
if (subRL!=null){
subRL.parent=parent;
}
TreeNode Pparent=parent.parent;
if (root==parent){
root=subR;
root.parent=null;
}else{
if (parent==Pparent.left){
Pparent.left=subR;
}else {
Pparent.right=subR;
}
subR.parent=Pparent;
}
subR.bf=0;
parent.bf=0;
}
3.新节点插入较高左子树的右侧:先左单旋再右单旋--左右双旋


java
private void rotateLR(TreeNode parent) {
TreeNode subL=parent.left;
TreeNode subLR=subL.right;
int bf=subLR.bf;
rotateLeft(parent.left);
rotateRight(parent);
if (bf==-1){
subL.bf=0;
subLR.bf=0;
parent.bf=1;
}else if(bf==1){
subL.bf=-1;
subLR.bf =0;
parent.bf=0;
}
}
- 新节点插入较高右子树的左侧---右左:先右单旋再左单旋--右左双旋


java
private void rotateRL(TreeNode parent) {
TreeNode subR=parent.right;
TreeNode subRL=subR.left;
int bf= subRL.bf;
rotateRight(parent.right);
rotateLeft(parent);
if (bf==-1){
parent.bf=0;
subRL.bf=0;
subR.bf=1;
}else if(bf==1) {// bf=0的情况在在上面的左旋与右旋已经调整完了
parent.bf=-1;
subRL.bf=0;
subR.bf=0;
}
}
AVL树的验证
- 验证其为二叉搜索树
如果中序遍历可得到一个有序的序列,就说明为二叉搜索树
java
//中序遍历的结果是有序的 就能说明当前树 一定是AVL树吗? 不一定的
public void inorder(TreeNode root){
if (root==null){
return;
}
inorder(root.left);
System.out.println(root.val+" ");
inorder(root.right);
}
- 验证其为平衡树
每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)
节点的平衡因子是否计算正确
java
public int height(TreeNode root){
if (root==null){
return 0;
}
int leftH=height(root.left);
int rightH=height(root.right);
return leftH > rightH ? leftH+1 : rightH+1;
}
public boolean isBalanced(TreeNode root){
if(root==null) return true;
int leftH=height(root.left);
int rightH=height(root.right);
if (rightH-leftH!=root.bf){
System.out.println("这个节点:"+root.val+"平衡因子异常");
return false;
}
return Math.abs(leftH-rightH)<=1
&&isBalanced(root.left)
&&isBalanced(root.right);
}