查找二叉平衡树与查找二叉树有什么区别呢?当要进行大规模删除操作时(先不考虑懒惰删除),会出现某种情况,高度会逐渐的变大,是因为我们总是把右边最小的叶子节点变为删除的点,再去删除右边最大的点,这就导致了高度变大,查找数据时间变长,显然这是要优化的。
- 我们需要在Node(内部节点类)中加入一个高度height的一个变量
- 思想:当插入的时候左节点和右节点的高度度相差深度超过1的时候,必须要旋转相应的节点来保持高度的平衡。
- 分为4种情况
对于平衡二叉树有4中情况
* 1.对&的左儿子的左子树进行一次插入
* 2.对&的左儿子的右子树进行一次插入
* 3.对&的右儿子的左子树进行一次插入
* 4.对&的右儿子的右子树进行一次插入
package tree;
/* 平衡查找二叉树 * 对于平衡二叉树有4中情况 * 1.对&的左儿子的左子树进行一次插入 * 2.对&的左儿子的右子树进行一次插入 * 3.对&的右儿子的左子树进行一次插入 * 4.对&的右儿子的右子树进行一次插入 */
public class AVLTree<AnyType extends Comparable<? super AnyType>>{
/* * 节点内部类 */
private static class AvlNode<AnyType>{
AnyType element; //数据(data)
AvlNode<AnyType> left; //左节点(Left child)
AvlNode<AnyType> right; //右节点(right child)
int height; //高度(height)
public AvlNode(AnyType x){
this(x, null, null);
}
public AvlNode(AnyType theElement, AvlNode<AnyType> lt, AvlNode<AnyType> rt){
element = theElement;
left = lt;
right = rt;
}
}
private AvlNode<AnyType> root; //根节点
//初始化操作
public AVLTree(){
root = null;
}
//判断是否为空树
public boolean isEmpty(){
return root == null;
}
//直接清空树
public void makeEmpty(){
root = null;
}
/* * 添加节点 */
public void insert(AnyType x){
root = insert(x, root);
}
/* * 前面的插入和ADT树没多大的区别,最大的区别就在于当插入数据的时候要先检查插入的数据相对的高度差 * 如果差值大于1,那么就要对应的进行旋转 */
private AvlNode<AnyType> insert(AnyType x, AvlNode<AnyType> t){
if(t == null)
return new AvlNode(x ,null, null);
int compareResult = x.compareTo(t.element); //比较当前节点的大小
if(compareResult > 0)
t.right = insert(x, t.right);
else if(compareResult < 0)
t.left = insert(x, t.left);
else
;
return balanced(t);
}
private static final int ALLOWED_IMBALANCE = 1;
private AvlNode<AnyType> balanced(AvlNode<AnyType> t){
if(t == null)
return t;
if(height(t.left) - height(t.right) > ALLOWED_IMBALANCE)
if(height(t.left.left) >= height(t.left.right))
t = rotateWithLeftChild(t);
else
t = doubleWithLeftChild(t);
else if(height(t.right) - height(t.left) > ALLOWED_IMBALANCE)
if(height(t.right.right) > height(t.right.left))
t = rotateWithRightChild(t);
else
t = doubleWithRightChild(t);
t.height = Math.max(height(t.left), height(t.right)) + 1;
return t;
}
/* * 每个节点的高度情况 只有三种情况 0 1 -1 */
private int height(AvlNode<AnyType> t){
return t == null ? -1 : t.height;
}
/* * 第一种情况:对&的左儿子的左子树进行一次插入(单旋转) k2 k1 k1 z ---> x k2 x y y z */
private AvlNode<AnyType> rotateWithLeftChild(AvlNode<AnyType> k2){
AvlNode<AnyType> k1 = k2.left;
k2.left = k1.right; //k2的左子树等于k1的右子树
k1.right = k2;
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
k1.height = Math.max(height(k1.left), k2.height) + 1;
return k1;
}
/* * 第二种情况:对&的左儿子的右子树进行一次插入(双旋转) * k3 k2 * k1 d ---> k1 k3 * a k2 a b c d * b c */
private AvlNode<AnyType> doubleWithLeftChild(AvlNode<AnyType> k3){
k3.left = rotateWithLeftChild(k3.left);
return rotateWithLeftChild(k3);
}
/* * 第三种情况:对&的右儿子的左子树进行一次插入(单旋转) k2 k1 z k1 ---> k2 y x y z x */
private AvlNode<AnyType> rotateWithRightChild(AvlNode<AnyType> k2){
AvlNode<AnyType> k1 = k2.right;
k2.right = k1.left; //k2的左子树等于k1的右子树
k1.left = k2;
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
k1.height = Math.max(height(k1.right), k2.height) + 1;
return k1;
}
/* * 第四种情况:对&的右儿子的右子树进行一次插入(双旋转) */
private AvlNode<AnyType> doubleWithRightChild(AvlNode<AnyType> k3){
k3.right = rotateWithRightChild(k3.right);
return rotateWithRightChild(k3);
}
/* * 同样,删除操作是最麻烦的操作,当删除一个节点的时候,也有可能会造成树的不平衡, * 所以也要调用balanced方法 */
public void remove(AnyType x){
remove(x, root);
}
private AvlNode<AnyType> remove(AnyType x, AvlNode<AnyType> t){
if(t == null)
return t;
int compareResult = x.compareTo(t.element);
if(compareResult < 0)
t.left = remove(x, t.left);
else if(compareResult > 0)
t.right = remove(x, t.right);
else if (t.left != null && t.right != null){
t.element = findMin(t.right).element;
t.right = remove(t.element, t.right);
}else
t = (t.left != null) ? t.left : t.right;
return balanced(t);
}
/* * 取树中的最小值(一直找左子树就ok) */
public AnyType findMin(){
if(isEmpty())
throw new NullPointerException();
return findMin(root).element;
}
private AvlNode<AnyType> findMin(AvlNode<AnyType> t){
if(t == null)
return null;
else if(t.left == null)
return t;
return findMin(t.left);
}
/* * 去树中的最大值(一直找右子树) */
public AnyType findMax(){
if(isEmpty())
throw new NullPointerException();
return findMax(root).element;
}
private AvlNode<AnyType> findMax(AvlNode<AnyType> t){
if(t == null)
return null;
else if(t.right == null)
return t;
return findMax(t.right);
}
public void printTree(){
if(isEmpty())
System.out.println("空树");
else
printTree(root);
}
private void printTree(AvlNode<AnyType> t){
if(t != null){
System.out.println("值:" + t.element+" " + ",高度:" + t.height);
printTree(t.left);
printTree(t.right);
}
}
public static void main(String[] args){
AVLTree<Integer> bst = new AVLTree<>();
bst.insert(1);
bst.insert(2);
bst.insert(3);
bst.insert(4);
bst.insert(5);
bst.insert(6);
bst.printTree();
System.out.println("最小值:" + bst.findMin());
}
}