AVL 树(平衡二叉树)
- AVL树是这样定义的一棵平衡二叉树:对任意节点,左子树和右子树的高度差不能超过1;
- AVL树中的每个节点标注了节点的高度;
- AVL树中的每个节点都有一个平衡因子,平衡因子指的是左右子树的高度差;
AVLTree 基础代码
- AVLTree的代码是基于之前BSTMap的代码改造的,每个节点中key和value,节点的可比较性体现在key上;
- 相较于BSTMap,AVLTree中的节点拥有表示节点高度的属性height,叶子节点的高度为1;
import java.util.ArrayList;
public class AVLTree<K extends Comparable<K>, V> {
private class Node{
public K key;
public V value;
public Node left, right;
public int height;
public Node(K key, V value){
this.key = key;
this.value = value;
left = null;
right = null;
height = 1;
}
}
private Node root;
private int size;
public AVLTree(){
root = null;
size = 0;
}
public int getSize(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
}
辅助方法 - 获取节点的高度值
- 节点null的高度为0,对获取节点高度的逻辑进行简单的封装,方便在更复杂逻辑中的使用 ;
// 获得节点node的高度
private int getHeight(Node node){
if(node == null)
return 0;
return node.height;
}
辅助方法 - 获取节点的平衡因子
- 如果节点是null,它的平衡因子是0;
- 如果节点不是null,平衡因子的计算方式为:左孩子的高 - 右孩子的高;
private int getBalanceFactor(Node node){
if(node == null)
return 0;
return getHeight(node.left) - getHeight(node.right);
}
add方法相关的逻辑改动
- 递归到底的情况并不需要修改,因为 node == null 的时候,新创建的节点只能作为整个二分搜索树的叶子节点,这是由二分搜索树的性质决定的,在AVLTree中,叶子节点的高度就是1;
- 递归到底的结果,在原本的二分搜索树中,只需一层层的向上返回,一层层的链接回整个二分搜索树,现在在引入节点的高度值后,将递归的结果一层层的向上返回已经不够了,因为新节点的加入,可能会影响新加入节点往上追溯的整个链表中节点高度值的变化,所以递归到底的结果在返回上层之后,除了要把根节点重新链入整棵二分搜索树中之外,还要更新这条链表中上层节点的高度值;具体更新的策略是:左右孩子中,高度更大的高度值加1;
- 在更新完节点(这条链表中除新添加的节点)的高度值后,还要计算一下节点的平衡因子,平衡因子的计算方式为:左孩子的高 - 右孩子的高;
- 将递归到底的结果链入整个二分搜索树,结算节点的高度值,计算节点的平衡因子,这3件事是递归到底的结果在一层层向上返回的过程中,每一层都需要做的操作;
// 向二分搜索树中添加新的元素(key, value)
public void add(K key, V value){
root = add(root, key, value);
}
// 向以node为根的二分搜索树中插入元素(key, value),递归算法
// 返回插入新节点后二分搜索树的根
private Node add(Node node, K key, V value){
if(node == null){
size ++;
return new Node(key, value);
}
if(key.compareTo(node.key) < 0)
node.left = add(node.left, key, value);
else if(key.compareTo(node.key) > 0)
node.right = add(node.right, key, value);
else // key.compareTo(node.key) == 0
node.value = value;
// 更新height
node.height = 1 + Math.max(getHeight(node.left), getHeight(node.right));
// 计算平衡因子
int balanceFactor = getBalanceFactor(node);
if(Math.abs(balanceFactor) > 1)
System.out.println("unbalanced : " + balanceFactor);
return node;
}