package com.xusheng.tree;
/**
* 实现平衡二叉树
* @author xusheng
*
* @param <T>
*/
public class AvlTree<T extends Comparable<? super T>> {
private AvlNode<T> root;
public AvlTree() {
this.root = null;
}
/**
* 对不平衡点的左儿子的左子树进行插入
* 将二叉树围绕不平衡点的左子节点进行左旋转
* @param k2
* @return
*/
private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2){
AvlNode<T> k1 = k2.leftNode;
k2.leftNode = k1.rightNode;
k1.rightNode = k2;
k2.height = Math.max(height(k2.leftNode), height(k2.rightNode))+1;
k1.height = Math.max(height(k1.leftNode), k2.height)+1;
return k1;
}
/**
* 对不平衡点的右儿子的右子树进行插入
* 将二叉树围绕不平衡点的右子节点进行旋转
* @param k2
* @return
*/
private AvlNode<T> rotateWithRightChild(AvlNode<T> k2){
AvlNode<T> k1 = k2.rightNode;
k2.rightNode = k1.leftNode;
k1.leftNode = k2;
k2.height = Math.max(height(k2.leftNode), height(k2.rightNode))+1;
k1.height = Math.max(height(k1.rightNode), k2.height)+1;
return k1;
}
/**
* 对不平衡点的左儿子的右子树进行插入
* 先将二叉树不平衡点的左儿子围绕它的右子节点旋转
* 后将二叉树围绕不平衡点的左儿子进行旋转
* @param k3
* @return
*/
private AvlNode<T> doubleRotateWithLeftChild(AvlNode<T> k3){
k3.leftNode = rotateWithRightChild(k3.leftNode);
return rotateWithLeftChild(k3);
}
/**
* 对不平衡点的右儿子的左子树进行插入
* 先将二叉树不平衡点的右儿子围绕它的左子节点旋转
* 后将二叉树围绕不平衡点的右儿子进行旋转
* @param k3
* @return
*/
private AvlNode<T> doubleRotateWithRightChild(AvlNode<T> k3){
k3.rightNode = rotateWithLeftChild(k3.rightNode);
return rotateWithRightChild(k3);
}
private static final int ALLOW_IMBALANCE = 1;//该常量表示数的高度差最多为1
/**
* 此方法用来对二叉树进行平衡
* @param node
* @return
*/
private AvlNode<T> balance(AvlNode<T> node){
if(node == null){
return node;
}
if(height(node.leftNode) - height(node.rightNode) > ALLOW_IMBALANCE){
if(height(node.leftNode.leftNode) >= height(node.leftNode.rightNode)){
node = rotateWithLeftChild(node);
}else{
node = doubleRotateWithLeftChild(node);
}
}else if(height(node.rightNode) - height(node.leftNode) > ALLOW_IMBALANCE){
if(height(node.rightNode.rightNode) >= height(node.rightNode.leftNode)){
node = rotateWithRightChild(node);
}else{
node = doubleRotateWithRightChild(node);
}
}
node.height = Math.max(height(node.leftNode), height(node.rightNode))+1;
return node;
}
private int height(AvlNode<T> t){
return t == null ? -1 : t.height;
}
public boolean isEmpty(){
return this.root == null;
}
public void insert(T element){
root = insert(element,root);
}
private AvlNode<T> insert(T element,AvlNode<T> node){
if(node == null){
return new AvlNode<T>(element,null,null);
}
int intCompare = element.compareTo(node.data);
if(intCompare < 0){
node.leftNode = insert(element,node.leftNode);
}else if(intCompare > 0){
node.rightNode = insert(element,node.rightNode);
}
return node;
}
public boolean contains(T element){
return contains(element,root);
}
private boolean contains(T element,AvlNode<T> node){
if(node == null){
return false;
}
int intCompare = element.compareTo(node.data);
if(intCompare < 0){
return contains(element,node.leftNode);
}else if(intCompare > 0){
return contains(element,node.rightNode);
}else{
return true;
}
}
public void remove(T element){
remove(element,root);
}
private AvlNode<T> remove(T element,AvlNode<T> node){
if(node == null){
return node;
}
int intCompare = element.compareTo(node.data);
if(intCompare < 0){
node.leftNode = remove(element,node.leftNode);
}else if(intCompare > 0){
node.rightNode = remove(element,node.rightNode);
}
else if(node.leftNode != null && node.rightNode != null){
node.data = findMin(node).data;
node.rightNode = remove(node.data,node.rightNode);
}else{
node = (node.leftNode != null) ? node.leftNode : node.rightNode;
}
return node;
}
private AvlNode<T> findMin(AvlNode<T> node){
if(node == null){
return null;
}else if(node.leftNode == null){
return node;
}else{
return findMin(node.leftNode);
}
}
private AvlNode<T> findMax(AvlNode<T> node){
if(node == null){
return null;
}
while(node.rightNode != null){
node = node.rightNode;
}
return node;
}
private class AvlNode<T>{
private T data;
private AvlNode<T> leftNode;
private AvlNode<T> rightNode;
private int height;
public AvlNode(T data, AvlNode<T> leftNode,AvlNode<T> rightNode) {
this.data = data;
this.leftNode = leftNode;
this.rightNode = rightNode;
}
public AvlNode(T element) {
this(element,null,null);
}
}
}