平衡二叉树:
平衡二叉树(AVL)是带平衡条件的二叉树,即每个节点的左子树和右子树高度最多差一的二叉查找树。
节点:
因为AVL必须保证左右两颗子数的平衡,所以定义一个高度变量表示该树的高度。再加上左右子树构成AVL的节点。
private class AvlNode{
public int element;
public AvlNode left;
public AvlNode right;
int height;
private AvlNode(int a,AvlNode b,AvlNode c) {
element = a;
left=b;
right=c;
height=0;
}
public AvlNode(int a) {
this(a, null, null);
}
}
插入:
在插入之后,只有那些从插入点到根结点的路径上的节点的平衡可能被改变,因为只有这些节点的子树可能发生变化,后续也只需要对这些节点进行平衡操作。
因为二叉树最多两个节点,所有插入后影响平衡的情况只有四种:
插入左节点的左子树中 LL 右旋
插入左节点的右子树中 LR 左旋再右旋
插入右子树的右子树中 RR 左旋
插入右子树的左子树中 RL 先右旋再左旋
以上内容转自维基百科AVL树
同二叉查找树的插入,但是每次插入后都要对该节点到根结点的所有节点进行平衡操作。
private AvlNode insert(int a,AvlNode t) {
if(t==null) {
return new AvlNode(a);
}
if(a<t.element) {
t.left = insert(a, t.left);
}else if(a>t.element) {
t.right = insert(a, t.right);
}else {
//一样不用插入
}
return balance(t);
}
平衡函数:
private AvlNode balance(AvlNode t) {
if(t==null) {
return t;
}
if(t.left.height>t.right.height) {
if(height(t.left.left)>=height(t.left.right)) {
t=rotateWithLeftChild(t);//右旋
}else {
t=doubleWithLeftChild(t);//先左旋再右旋
}
}else if(t.right.element>t.left.element) {
if(height(t.right.right)>=height(t.right.left)) {
t=rotateWithRightChild(t);//左旋
}else {
t=doubleWithRightChild(t);//先右旋再左旋
}
}
t.height = Math.max(t.left.height,t.right.height)+1;
return t;
}
左旋函数:
private AvlNode rotateWithRightChild(AvlNode t) {
AvlNode avlNode = t.right;
t.right=avlNode.left;
avlNode.left = t;
t.height = Math.max(t.left.height, t.right.height);
avlNode.height = Math.max(t.height, avlNode.right.height);
return avlNode;
}
右旋:
private AvlNode rotateWithLeftChild(AvlNode t) {
AvlNode avlNode = t.left;
t.left = avlNode.right;
avlNode.right = t;
t.height = Math.max(t.left.height, t.right.height)+1;
avlNode.height = Math.max(avlNode.height, t.height)+1;
return avlNode;
}
先左旋再右旋:
private AvlNode doubleWithLeftChild(AvlNode t) {
t.left=rotateWithRightChild(t.left);
rotateWithLeftChild(t);
return t;
}
先右旋再左旋:
private AvlNode doubleWithRightChild(AvlNode t) {
t.right=rotateWithLeftChild(t.right);
rotateWithRightChild(t);
return t;
}
删除:
删除操作与插入类似,删除之后再做平衡就好。但是删除有一种特殊情况就是删除之后左子树或右子树的两个节点高度相等的情况,例如上图中左左情况经过右旋得到的下面的图,如果再将5节点删除就出现这种情况。
但是这种情况也只需要经过单旋就能得到,所有在上面平衡函数判断语句中加入=号。
private AvlNode remove(int a,AvlNode t) {
if(t==null) {
return t;
}
if(a<t.element) {
t.left = remove(a, t.left);
}else if(a>t.element) {
t.right = remove(a, t.right);
}else {
if(t.left!=null&&t.right!=null) {
t.element = findMin(t.right).element;
t.right = remove(findMin(t.right).element, t.right);
}else {
t= (t.left!=null)?t.left:t.right;
}
}
return balance(t);
}
AVL
public class BlanceTree {
private AvlNode insert(int a,AvlNode t) {
if(t==null) {
return new AvlNode(a);
}
if(a<t.element) {
t.left = insert(a, t.left);
}else if(a>t.element) {
t.right = insert(a, t.right);
}else {
}
return balance(t);
}
private int height(AvlNode t) {
return t==null?-1:t.height;
}
private AvlNode balance(AvlNode t) {
if(t==null) {
return t;
}
if(t.left.height>t.right.height) {
if(height(t.left.left)>=height(t.left.right)) {
t=rotateWithLeftChild(t);
}else {
t=doubleWithLeftChild(t);
}
}else if(t.right.element>t.left.element) {
if(height(t.right.right)>=height(t.right.left)) {
t=rotateWithRightChild(t);
}else {
t=doubleWithRightChild(t);
}
}
t.height = Math.max(t.left.height,t.right.height)+1;
return t;
}
private AvlNode doubleWithRightChild(AvlNode t) {
t.right=rotateWithLeftChild(t.right);
rotateWithRightChild(t);
return t;
}
private AvlNode rotateWithRightChild(AvlNode t) {
AvlNode avlNode = t.right;
t.right=avlNode.left;
avlNode.left = t;
t.height = Math.max(t.left.height, t.right.height);
avlNode.height = Math.max(t.height, avlNode.right.height);
return avlNode;
}
private AvlNode doubleWithLeftChild(AvlNode t) {
t.left=rotateWithRightChild(t.left);
rotateWithLeftChild(t);
return t;
}
private AvlNode rotateWithLeftChild(AvlNode t) {
AvlNode avlNode = t.left;
t.left = avlNode.right;
avlNode.right = t;
t.height = Math.max(t.left.height, t.right.height)+1;
avlNode.height = Math.max(avlNode.height, t.height)+1;
return avlNode;
}
private AvlNode remove(int a,AvlNode t) {
if(t==null) {
return t;
}
if(a<t.element) {
t.left = remove(a, t.left);
}else if(a>t.element) {
t.right = remove(a, t.right);
}else {
if(t.left!=null&&t.right!=null) {
t.element = findMin(t.right).element;
t.right = remove(findMin(t.right).element, t.right);
}else {
t= (t.left!=null)?t.left:t.right;
}
}
t.height = Math.max(t.left.height, t.right.height)-1;
return balance(t);
}
private AvlNode findMin(AvlNode t) {
if(t==null) {
return null;
}
if(t.left==null) {
return t;
}else {
return findMin(t.left);
}
}
private class AvlNode{
public int element;
public AvlNode left;
public AvlNode right;
int height;
private AvlNode(int a,AvlNode b,AvlNode c) {
element = a;
left=b;
right=c;
height=0;
}
public AvlNode(int a) {
this(a, null, null);
}
}
}