平衡二叉树
-
本质是二叉查找树的一种
-
每个节点的左右子树的高度差的绝对值(平衡因子)最多为1 ,| leftTreeHeightmax - rightTreeHeightmax| <= 1
-
avi树图 (当左子树或是右子树,为空,默认值是-1)
旋转
-
当avi的平衡因子大于1的时候,就会打破avi的平衡,这时我们需要左旋转或右旋转,来重新让它平衡。
-
对于AVI的旋转分为四种情况,分别是左左型,右右型,左右型,右左型
-
左左型 — 像图中一样,所有节点都偏向左边的情况,这个时候我们需要右旋操作
右旋:即顺时针旋转两个节点,使父节点4被左节点1取代,而节点4成为节点1的右节点。(总结:平衡因子为2的节点,成为其左子树的右子树,原来左子树的右子树,成为其的左子树,平衡因子在从新更新)
-
右右型 – 节点集中在右边,需要左旋操作(平衡因子为2的点,成为其右子树的左子树,原来右子树的左子树,变成其右子树)
-
右左型 – 先选择右旋(将其变成右右型),在旋转左旋 (先将其变成右右型,在依照右右型来处理)
-
左右型 — 先将其变成左左型
public class Node {
int data;
Node lchild;
Node rchild;
int height;
public Node(int data) {
this.data = data;
}
}
public class AVLTree {
private Node root;
// 记录节点的高度
private int height(Node node) {
if (node == null) {
return -1;
} else {
return node.height;
}
}
// 右右型 左旋
private Node L_Rotate(Node node) {
Node temp;
// 进行旋转
temp = node.rchild;
node.rchild = temp.lchild;
temp.lchild = node;
// 重新计算高度
node.height = Math.max(height(node.lchild), height(node.rchild)) + 1;
temp.height = Math.max(height(temp.lchild), height(temp.rchild)) + 1;
return temp;
}
// 左左型 右旋
private Node R_Rotate(Node node) {
Node temp;
// 进行旋转
temp = node.lchild;
node.lchild = temp.rchild;
temp.rchild = node;
// 重新计算高度
node.height = Math.max(height(node.lchild), height(node.rchild)) + 1;
temp.height = Math.max(height(temp.lchild), height(temp.rchild)) + 1;
return temp;
}
// 左右型 先进行左旋在进行右旋
private Node L_R_Rotate(Node node) {
// 对左子节点进行左旋
node.lchild = L_Rotate(node.lchild);
// 对节点进行右旋
return R_Rotate(node);
}
// 右左型 先进性右旋在进行左旋
private Node R_L_Rotate(Node node) {
// 对右子节点进行右旋
node.rchild = R_Rotate(node.rchild);
// 对节点进行左旋
return L_Rotate(node);
}
public void insert(int data) {
root = insert(data, root);
}
// 插入操作
private Node insert(int data, Node node) {
if (node == null) {
node = new Node(data);
} else if (data < node.data) {
// 向左子节点递归插入
node.lchild = insert(data, node.lchild);
// 如果左子节点的高度比右子节点的高度大2 则进行旋转调整
if (height(node.lchild) - height(node.rchild) == 2){
if (data < node.lchild.data) {
// 左左型
node = R_Rotate(node);
} else {
// 左右型
node = R_L_Rotate(node);
}
}
} else if (data > node.data) {
// 向右子节点递归插入
node.rchild = insert(data, node.rchild);
// 如果右子节点的高度比左子节点的高度大2 则进行旋转调整
if (height(node.rchild) - height(node.lchild) == 2) {
if (data > node.rchild.data) {
// 右右型
node = L_Rotate(node);
} else {
// 右左型
node = R_L_Rotate(node);
}
}
}
// 如果 data = node.data 这个节点在树上存在 什么也不做
node.height = Math.max(height(node.lchild), height(node.rchild)) + 1;
return node;
}
// 中序遍历AVL树
public void inOrder() {
inOrder(root);
}
private void inOrder(Node node) {
if (node != null) {
inOrder(node.lchild);
System.out.println(node.data);
inOrder(node.rchild);
}
}
}