平衡二叉树
Balanced Binary Tree
,左右子树高度差不超过1,因此能够保证很好的插入和查找效率
# 定义
-
左右子树高度差不超过1
-
左右子树也是平衡二叉树
-
空二叉树是平衡二叉树
#实现
节点定义
package com.piziwang.tree.avltree;
/**
* 平衡二叉树 Balance Binary Tree
* @author PIZIWANG
* @date 2022-05-05 21:37
**/
public class AVLTree<T extends Comparable>{
/**树的根节点*/
AVLTreeNode<T> mRoot;
/**
* avltree节点,内部类
*/
public class AVLTreeNode<T extends Comparable>{
public T key;
int height;
AVLTreeNode<T> left;
AVLTreeNode<T> right;
public AVLTreeNode(T key, AVLTreeNode<T> left, AVLTreeNode<T> right) {
this.key = key;
this.left = left;
this.right = right;
}
}
/**
* 获取树的高度
* @return 树的高度
*/
public int height(){
return height(mRoot);
}
private int height(AVLTreeNode<T> tree) {
if (tree != null) {
return tree.height;
}
return 0;
}
/**
* 获取两个数中较大的那一个
*/
private int max(int x,int y){
return x>y ? x : y;
}
/**
* LL旋转是围绕"失去平衡的AVL根节点"进行的
* @param k2 k2 失去平衡的根节点
* @return {@link AVLTreeNode}<{@link T}>
*/
private AVLTreeNode<T> leftLeftRotation(AVLTreeNode<T> k2){
AVLTreeNode<T> k1;
k1 = k2.left;
k2.left=k1.right;
k1.right=k2;
k2.height = max(height(k2.left),height(k2.right))+1;
k1.height = max(height(k1.left), k2.height)+1;
return k1;
}
/**
* RR旋转是围绕"失去平衡的AVL根节点"进行的
* @param k1 k1 失去平衡的根节点
* @return {@link AVLTreeNode}<{@link T}>
*/
private AVLTreeNode<T> rightRightRotation(AVLTreeNode<T> k1){
AVLTreeNode<T> k2;
k2 = k1.right;
k1.right=k2.left;
k2.left=k1;
k1.height = max(height(k1.left),height(k1.right))+1;
k2.height = max(height(k2.right), k1.height)+1;
return k2;
}
/**
* LR失去平衡的情况,需要经过两次旋转才能让AVL树 1.围绕根节点左节点,RR, 2.围绕根节点 LL
* @param k3 k1 失去平衡的根节点
* @return {@link AVLTreeNode}<{@link T}>
*/
private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> k3){
k3.left = rightRightRotation(k3.left);
return leftLeftRotation(k3);
}
/**
* Rl失去平衡的情况,需要经过两次旋转才能让AVL树 1.围绕根节点右节点,LL, 2.围绕根节点 RR
* @param k1 失去平衡的根节点
* @return {@link AVLTreeNode}<{@link T}>
*/
private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> k1){
k1.right = leftLeftRotation(k1.right);
return rightRightRotation(k1);
}
/**
* 插入节点
* @param key
*/
public void insert(T key){
mRoot= insert(mRoot,key);
}
public void insert(T []key){
for (int i = 0; i < key.length; i++) {
mRoot= insert(mRoot,key[i]);
}
}
private AVLTreeNode<T> insert(AVLTreeNode<T> tree, T key) {
if (tree == null) {
tree = new AVLTreeNode<T>(key,null,null);
if (tree==null) {
System.out.println("create failed");
return null;
}
}else {
// 比较带插入值和当前值节点的大小
int cmp = key.compareTo(tree.key);
if (cmp < 0) {
//待插入值小于当前值,插在左侧
tree.left=insert(tree.left,key);
//插入节点后,判断是否导致不平衡
if(height(tree.left)-height(tree.right)==2){
if (key.compareTo(tree.left.key)<0) {
// 左左
tree = leftLeftRotation(tree);
}else {
// 左右
tree = leftRightRotation(tree);
}
}
}else if (cmp>0) {
//待插入值大于当前值,插在右侧
tree.right = insert(tree.right, key);
// 判断是否导致不平衡
if(height(tree.right) - height(tree.left) ==2){
if (key.compareTo(tree.right.key) > 0) {
// 右右
tree = rightRightRotation(tree);
}else {
tree = rightLeftRotation(tree);
}
}
}else {
System.out.println("添加失败,值已存在");
}
}
tree.height = max(height(tree.left),height(tree.right))+1;
return tree;
}
/**
* 删除节点
*/
public void remove(T key){
AVLTreeNode<T> z = search(key);
if(z != null){
mRoot = remove(mRoot,z);
}
}
private AVLTreeNode<T> remove(AVLTreeNode<T> tree, AVLTreeNode<T> z) {
if (tree == null || z == null) {
return null;
}
int cmp = z.key.compareTo(tree.key);
if (cmp < 0) {
// 待删除节点在左子树上
tree.left = remove(tree.left,z);
// 删除节点后,若AVL树失去平衡,则进行相应的调节。
if (height(tree.right) - height(tree.left) == 2) {
AVLTreeNode<T> r = tree.right;
if (height(r.left) > height(r.right)) {
tree = rightLeftRotation(tree);
} else {
tree = rightRightRotation(tree);
}
}
}else if (cmp>0) {
// 待删除节点在右子树上
tree.right = remove(tree.right, z);
// 删除节点后,若AVL树失去平衡,则进行相应的调节。
if (height(tree.left) - height(tree.right) == 2) {
AVLTreeNode<T> l = tree.left;
if (height(l.right) > height(l.left)) {
tree = leftRightRotation(tree);
} else {
tree = leftLeftRotation(tree);
}
}
}else {
// 待删除节点就是当前节点
// 1.tree的左右子树都非空
if(tree.left !=null && tree.right != null){
if(height(tree.left)>height(tree.right)){
/* tree的左子树比右子树高;
则(01)找出tree的左子树中的最大节点
(02)将该最大节点的值赋值给tree。
(03)删除该最大节点。
这类似于用"tree的左子树中最大节点"做"tree"的替身;
采用这种方式的好处是: 删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。*/
AVLTreeNode<T> max = maximum(tree.left);
tree.key=max.key;
tree.left=remove(tree.left, max);
}else {
/*tree的左子树不比右子树高(即它们相等,或右子树比左子树高1)
则(01)找出tree的右子树中的最小节点
(02)将该最小节点的值赋值给tree。
(03)删除该最小节点。
这类似于用"tree的右子树中最小节点"做"tree"的替身;
采用这种方式的好处是: 删除"tree的右子树中最小节点"之后,AVL树仍然是平衡的。*/
AVLTreeNode<T> min = minimum(tree.right);
tree.key=min.key;
tree.right=remove(tree.right,min);
}
}else {
// 2有一个子树是空的,直接用子树替代
AVLTreeNode<T> tmp = tree;
tree = (tree.left!=null) ? tree.left : tree.right;
tmp = null;
}
}
return tree;
}
/**
* 获取最大的节点
*/
public T maximum(){
AVLTreeNode<T> maximum = maximum(mRoot);
if (maximum != null) {
return maximum.key;
}else {
return null;
}
}
private AVLTreeNode<T> maximum(AVLTreeNode<T> tree) {
if (tree.right != null) {
//最大节点在右子树
return maximum(tree.right);
}else {
return tree;
}
}
/**
* 获取最小的节点
*/
public T minimum(){
AVLTreeNode<T> minimum = minimum(mRoot);
if (minimum != null) {
return minimum.key;
}else {
return null;
}
}
private AVLTreeNode<T> minimum(AVLTreeNode<T> tree) {
if (tree.left != null) {
//最大节点在右子树
return maximum(tree.left);
}else {
return tree;
}
}
/**
* 查找节点
* @param key
* @return
*/
public AVLTreeNode<T> search(T key) {
return search(mRoot,key);
}
private AVLTreeNode<T> search(AVLTreeNode<T> tree, T key) {
if (tree == null) {
return null;
}else {
if (key.compareTo(tree.key)>0) {
return search(tree.right,key);
}else if (key.compareTo(tree.key)<0) {
return search(tree.left,key);
}else {
return tree;
}
}
}
/**
* 打印
* @param tree 树
* @param key 关键
* @param direction 0- 跟节点 1 右子树 -1 左子树
*/
private void print(AVLTreeNode<T> tree, T key, int direction) {
if(tree != null) {
// tree是根节点
if(direction==0)
{
System.out.printf("%2d is root\n", tree.key);
} else // tree是分支节点
{
System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction==1?"right" : "left");
}
print(tree.left, tree.key, -1);
print(tree.right,tree.key, 1);
}
}
/**
* 打印
*/
public void print() {
if (mRoot != null) {
print(mRoot, mRoot.key, 0);
}
}
}