目录
平衡二叉树和AVL树是在二分搜索树的基础上进行讲解
回忆二分搜索树的问题:
添加数据 :是按照顺序添加的 32145
每个节点的左节点小于根节点,每个节点的右节点都大于根节点
一、AVL
AVL树得名于它的发明者G.M.Adelson-Velsky 和 E.M.Landis
AVL树最早发明的自平衡二分搜索树
二、平衡二叉树
平衡二叉树的要求:对于任意一个节点,左子树和右子树的高度差不能超过1
(1)一颗满二叉树和完全二叉树是平衡二叉树
(2)线段树也是平衡二叉树
(3)如果按照以前的二分搜索树的方式,分别添加节点 2 和 7 ,此棵树就不是平衡二叉树。
为了能保持这课二叉树的平衡,就要标注每个节点的高度
计算出平衡因子(左右子树的高度差) 最终高度差不能相差1
三、代码实现
(1)获取节点高度
//获取节点高度
private int getheight(Node node) {
if (node == null) {
return 0;
}
return node.heigth;
}
(2)获取节点的平衡因子
//获取平衡因子
private int getBalance(Node node) {
if (node == null) {
return 0;
}
return getheight(node.left) - getheight(node.right);
}
(3)判断是不是二分搜索树
//判断是否是二分搜索树
public boolean isBST() {
return isBST(root);
}
(4)根据中序遍历的结果进行判断是不是二分搜索树
//中序遍历的结果进行判断 左 中 右
private boolean isBST(Node node) {
List<T> list = new ArrayList<>();
inorderTraversal(node, list);
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i).compareTo(list.get(i + 1)) > 0) {
return false;
}
}
return true;
}
(5)中序遍历
//中序遍历
private void inorderTraversal(Node node, List<T> list) {
if (node == null) {
return;
}
inorderTraversal(node.left, list);
list.add(node.val);
inorderTraversal(node.right, list);
}
(6)判断是否是平衡二叉树
//判断是否是平衡二叉树
public boolean isBalanceTree() {
return isBalanceTree(root);
}
private boolean isBalanceTree(Node node) {
//如果根节点为空,也为平衡树
if (node == null) {
return true;
}
//根节点不为空情况如下 平衡因子的绝对值
int balance = Math.abs(getBalance(node));
if (balance > 1) {
return false;
}
return isBalanceTree(node.left) && isBalanceTree(node.right);
}
四、测试
AVLtree<Integer> AVLtree =new AVLtree();
int[] arr = {
23,12,11,5,6,8,25};
for (int i = 0; i <arr.length; i++) {
AVLtree.add(arr[i]);
}
System.out.println(AVLtree.isBST());
System.out.println(AVLtree.isBalanceTree());
System.out.println(AVLtree);
五、AVL的左旋转和右旋转
(1)维护平衡的时机
加入节点后,沿着节点向上维护平衡性
(2)插入的元素在不平衡节点的左侧的左侧
依次插入 12 8 5
右旋维持平衡
第一步:
第二步:
右旋代码实现
//AVL树的右旋 根节点为x
public Node rightrotate(Node x) {
Node y = x.left; //将根节点的左节点赋值为 y节点
Node t2 = y.right; //将y节点的右侧赋值为t2 断开右侧节点
y.right = x; //右旋转,将根节点赋值给y的右侧
x.left = t2; //将断开的t2 ,连接到x根节点的左侧
//更新height
x.heigth = Math.max(getheight(x.left), getheight(x.right)) + 1;
y.heigth = Math.max(getheight(y.left), getheight(y.right)) + 1;
return y;
}
(3)插入的元素在不平衡节点的右侧的右侧
依次插入 5 8 12
左旋维持平衡
第一步:
第二步:
左旋代码实现
//AVL树的左旋
public Node leftrotate(Node x) {
Node y = x.right; //根节点为x ,将根节点的右侧赋值为y节点
Node t2 = y.left; //将y节点的左侧断开 ,并赋值为t2
y.left = x; //将节点x赋值在y节点的左侧
x.right = t2; //将断开的t2 ,连接到x节点的右侧
//更新height
x.heigth = Math.max(getheight(x.left), getheight(x.right)) + 1;
y.heigth = Math.max(getheight(y.left)