數據結構與算法-樹-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);
}
}
}