数据结构与算法-树-AVL树
一棵AVL树有如下必要条件:
- 它必须是二叉查找树。
- 条件二:每个节点的左子树和右子树的高度差至多为1。
使用AVL树的原因
我们为了提高查找效率而使用了二叉搜索树,这使得理论上能将查找时间降到O(log(n))的程度,然而实际上这是不可能的,像是1,2,3,4,5.。。。这样的插入方式很可能会导致二叉搜索树的单链过长而无法提高效率。这时候就有了AVL树(平衡二叉树),通过旋转可以降低二叉树的高度。
树结构
有头结点
class TreeNode{
public int val;
public int height;
public TreeNode father;
public TreeNode left;
public TreeNode right;
public TreeNode(int val,int height,TreeNode left,TreeNode right,TreeNode father) {
this.val=val;
this.height=height;
this.father=father;
this.left=left;
this.right=right;
}
}
private int getHeight(TreeNode node) {
return node==null?0:node.height;
}
插入后不平衡的状态进行旋转
LL
实现代码:
private void LL(TreeNode node) {
TreeNode father = node.father;
TreeNode x = node.left;
if(father.left==node) {
father.left=x;
}else {
father.right=x;
}
x.father=father;
node.left = x.right;
if(x.right!=null) {
x.right.father=node;
}
x.right=node;
node.father=x;
node.height=Math.max(getHeight(node.left),getHeight(node.right))+1;
x.height=Math.max(getHeight(x.left),getHeight(x.right))+1;
}
RR
实现代码
private void RR(TreeNode node) {
TreeNode father = node.father;
TreeNode r = node.right;
if(father.left==node) {
father.left=r;
}else {
father.right=r;
}
r.father=father;
node.right = r.left;
if(r.left!=null) {
r.left.father=node;
}
r.left=node;
node.father=r;
node.height=Math.max(getHeight(node.left),getHeight(node.right))+1;
r.height=Math.max(getHeight(r.left),getHeight(r.right))+1;
}
LR
实现代码
private void LR(TreeNode node) {
TreeNode father = node.father;
TreeNode x = node.left;
if(father.left==node) {
father.left=x;
}else {
father.right=x;
}
x.father=father;
node.left = x.right;
if(x.right!=null) {
x.right.father=node;
}
x.right=node;
node.father=x;
node.height=Math.max(getHeight(node.left),getHeight(node.right))+1;
x.height=Math.max(getHeight(x.left),getHeight(x.right))+1;
}
RL
实现代码:
private void RL(TreeNode node) {
TreeNode father = node.father;
TreeNode x = node.right;
if(father.left==node) {
father.left=x;
}else {
father.right=x;
}
x.father=father;
node.right = x.left;
if(x.left!=null) {
x.left.father=node;
}
x.left=node;
node.father=x;
node.height=Math.max(getHeight(node.left),getHeight(node.right))+1;
x.height=Math.max(getHeight(x.left),getHeight(x.right))+1;
}
删除
- 叶子节点直接删除
- 只有左节点或右节点,直接删除当前节点,重置父子连接关系
- 有左节点和右节点,找到较高的子树中最接近当前节点的节点,替换当前节点。
- 以上情况,进行删除之后重新平衡二叉树,如果不平衡的话。
private void delete(TreeNode node) {
if(node==null) {
return;
}
TreeNode father = node.father;
TreeNode nNode = null;
if(node.left==null&&node.right==null) {
}else if(node.left==null&&node.right!=null) {
nNode = node.right;
}else if(node.left!=null&&node.right==null) {
nNode = node.left;
}else if(node.left!=null&&node.right!=null) {
if(getHeight(node.left)>getHeight(node.right)) {
nNode = node.left;
while(nNode.right!=null) {
nNode = nNode.right;
}
if(nNode == node.left) {
nNode.right = node.right;
}
}else {
nNode = node.right;
while(nNode.left!=null) {
nNode = nNode.left;
}
if(nNode == node.right) {
nNode.left=node.left;
}
}
}
if(father.right==node) {
father.right=nNode;
}else {
father.left=nNode;
}
TreeNode bottom = null;
if(nNode==null) {
bottom = father;
}else {
bottom = nNode.father;
if(bottom.right==nNode) {
bottom.right=null;
}else {
bottom.left=null;
}
nNode.father=father;
}
while(bottom!=root) {
bottom.height = Math.max(getHeight(bottom.left), getHeight(bottom.right))+1;
toBalance(bottom);
bottom.height = Math.max(getHeight(bottom.left), getHeight(bottom.right))+1;
bottom=bottom.father;
}
size--;
}
private void toBalance(TreeNode node) {
int l = getHeight(node.left);
int r = getHeight(node.right);
if(l-r==-2) {
if(getHeight(node.right.left)<getHeight(node.right.right)) {
RR(node);
}else {
RL(node);
}
}else if(l-r==2) {
if(getHeight(node.left.left)<getHeight(node.left.right)) {
LR(node);
}else {
LL(node);
}
}
}