二叉树
AVL平衡树
起名原因:G.M.Adelson-Velsky和E.M.Landis
它是一种最早的自平衡二分搜索树结构;满二叉树一定是平衡树,高度最低;而完全二叉树也是平衡二叉树,叶子结点深度相差不为1;
AVL平衡树的定义
对于任意一个节点,左子树和右子树的高度差不能超过1;如图是平衡树;
平衡树的调整
既然是平衡树,当我们进行添加删除等操作后,该树有可能就不是平衡树了,所以我们需要将它调整为平衡树;那问题就来了,怎末调整,什么时候调整呢;首先标记节点的高度,再计算平衡因子,也就是该节点的左右子树的高度差;在我们对树进行添加删除元素时需要维护该树,从该操作节点向上回溯维护平衡性。
既然需要调整就会出现不同的情况,如下:
LL旋转
对于第一种情况添加元素在该节点左孩子的左孩子,如图所示进行操作;
就相当于将当前节点y向右旋转下来作为其左孩子x的右孩子,但是当前节点y的左孩子为子树可能存在右孩子,所以我们需要先将其右孩子保存再赋给当前节点y作为左孩子;主要是因为其值存在上图的大小关系,也就是不能改变二分搜索树的性质;具体就是x.right = y;y.left = T3;
RR旋转
插入的元素在不平衡节点的右孩子的右孩子,我们只需将其向左旋转,让不平衡节点y分支作为其右孩子的左孩子,还是一样其右孩子x的左孩子可能有元素,所以需要保存起来,让不平衡节点称为其右孩子的左孩子,然后将保存的值作为y的右孩子;也就是x.left = y;y.right=T3;
LR旋转
插入的元素在不平衡节点的左孩子的右孩子,先对x进行左旋转RR,再对y进行右旋转LL。
RL旋转
插入的元素再不平衡的节点的右孩子的左孩子,它的操作和LR旋转相反,先对x进行右旋转LL,再对y进行左旋转RR即可;
平衡树代码实现
1.平衡树的节点类及属性定义
节点类定义和TreeMap的节点类定义无非是多一个高度属性;而属性定义是一致的。
package tree;
import ifce.List;
import ifce.Map;
import ifce.Set;
import lianbiao.LinkedList;
import linestract.ArrayList;
public class AVLTreeMap<K extends Comparable<K>,V> implements Map<K,V> {
private class Node{
public K key;
public V value;
public int height;
public Node left;
public Node right;
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 AVLTreeMap(){
root = null;
size = 0;
}
2.辅助函数
2.1根据所给节点和key查找相应的节点
//以node为根的子树中,查找key所在的结点;
private Node getNode(Node node,K key){
if(node == null){
return null;
}
if(key.compareTo(node.key)<0){
return getNode(node.left,key);
}else if(key.compareTo(node.key)>0){
return getNode(node.right,key);
}else{
return node;
}
}
2.2获取某个节点高度
根据所给节点判断是否为null,为null返回0,否则返回其高度即可。
//获取某个结点的高度;
private int getHeight(Node node){
if(node == null){
return 0;
}
return node.height;
}
2.3计算某个节点的平衡因子
若是传入节点为null,返回0,否则返回其左右孩子的高度差即可。
//计算某个结点的平衡因子;(左右孩子高度差);
private int getBalanceFactor(Node node){
if(node == null){
return 0;
}
return getHeight(node.left) - getHeight(node.right);
}
2.4验证是否为二分搜索树,以及是否为平衡树
验证是否为二分搜索树,我们是将该树进行中序遍历存储到list集合中,然后遍历集合,只要后面的值比前面的值大(所有)就是二分搜索树。
验证是否为平衡树,则是自己再实现一个从根结点遍历是否为平衡树,如果传入的节点为null,则是平衡树;如果不为空,则需要获取该节点的平衡因子,判断平衡因子的绝对值是否超过1,超过则不是,否则就是平衡的。但是需要从根到子孙,所以根符合并不代表整个树是平衡树,还有它的所分支是平衡的,左右分支的每个节点都是平衡的才是平衡树;
//验证是否为二分搜索树;
public boolean isBST(){
ArrayList<K> list = new ArrayList<>();
inOrderKeys(root,list);
for(int i=1;i<list.size();i++){
if(list.get(i-1).compareTo(list.get(i))>0){
return false;
}
}
return true;
}
private void inOrderKeys(Node node,ArrayList<K> list) {
if(node == null){
return;
}
inOrderKeys(node.left,list);
list.add(node.key);
inOrderKeys(node.right,list);
}
//验证是否为平衡树;
public boolean isBalanced(){
return isBalanced(root);
}
private boolean isBalanced(Node node) {
if(node == null){
return true;
}
//从根到子孙,所以根符合并不代表整个树是平衡树,还有它的所分支是平衡的,左右分支的每个节点都是平衡的才是平衡树;
int balancedFactor = getBalanceFactor(node);
if(Math.abs(balancedFactor)>1){
return false;
}
return isBalanced(node.left) && isBalanced(node.right);
}
2.5左右旋转实现
实现图分析在上方,只是旋转后需要更新动过节点的高度,然后将新节点向上返回;
public Node leftRotate(Node y){
Node x = y.right;
Node T3