您的位置:首页 > 编程语言 > Java开发

Java实现平衡二叉树(AVL树)

2017-12-21 17:01 736 查看

一、定义

AVL树:左右子树高度之差的绝对值不超过1的二叉排序树

平衡因子:左子树的高度减去右子树的高度的差

失去平衡的最小子树:以距离插入结点最近,且平衡因子绝对值大于1的结点作为根的子树

二、插入、调整操作

2.1 定义结点

private TreeNode<T> root;//根节点
private Comparator<? super T> cmp;

//内部类
public static class TreeNode<T>{
T data;
TreeNode<T> left;
TreeNode<T> right;
int height;

TreeNode(T data, TreeNode<T> lt, TreeNode<T> rt){
data= data;
left = lt;
right = rt;
height = 0;
}
}


2.2 插入节点

有必要解释下递归插入:

①递归结束的条件是
t==null
,②最后的一个
insert
方法的返回值是
new TreeNode<T>(x,null, null)
知道这两个点就很好理解了

public void insert(T data){
root = insert(data, root);
}

/**
* 插入节点,如果根节点不存在,则把待插入节点设为根节点
* @param x 待插入节点
* @param t 根节点
* @return
*/
private TreeNode<T> insert(T x, TreeNode<T> t){
if(t == null)
return new TreeNode<T>(x, null, null);
int compareResult = myCompare(x, t.data);
if(compareResult < 0){//插入左子树
t.left = insert(x, t.left);
if(height(t.left)-height(t.right) == 2){
if(myCompare(x, t.left.data) < 0)
t = rotateWithLeftChild(t);//左左情况
else
t = doubleWithLeftChild(t);//左右情况
}
}else if(compareResult > 0){//插入右子树
t.right = insert(x, t.right);
if(height(t.right)-height(t.left) == 2){
if(myCompare(x, t.right.data) < 0)
t = doubleWithRightChild(t);//右左情况
else
t = rotateWithRightChild(t);//右右情况
}
}
//更新height值
t.height = Math.max(height(t.left), height(t.right))+1;
return t;
}


2.3 LL 调整



/**
* 可将LL情况变平衡,也可将RL情况变成RR
* @param k2
* @return
*/
private TreeNode<T> rotateWithLeftChild(TreeNode<T> k2){
TreeNode<T> k1 = k2.left;
k2.left = k1.right; //  将RL情况变成RR
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;
}


2.4 LR 调整



/**
* 左右情况(LR)、双旋转
* 1、先右右再左左
* @param k3
* @return
*/
private TreeNode<T> doubleWithLeftChild(TreeNode<T> k3){
try{
k3.left = rotateWithRightChild(k3.left);
}catch(NullPointerException e){
throw e;
}
return rotateWithLeftChild(k3);
}


2.5 RR 调整



/**
* 可将RR情况变平衡,也可将LR情况变成LL
* @param k2
* @return
*/
private TreeNode<T> rotateWithRightChild(TreeNode<T> k2){
TreeNode<T> k1 = k2.right;
k2.right = k1.left;//将LR情况变成LL
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;
}


2.6 RL 调整



/**
* 右左情况(RL),双旋转
* 1、先左左再右右
* @param k3
* @return
*/
private TreeNode<T> doubleWithRightChild(TreeNode<T> k3){
try{
k3.right = rotateWithLeftChild(k3.right);
}catch(NullPointerException e){
throw e;
}
return rotateWithRightChild(k3);
}


2.7 删除节点

递归的结束条件:
t == null


/**
* 删除节点
* @param x
* @param t 根节点
* @return
*/
private TreeNode<T> remove(T x, TreeNode<T> t){
if(t == null)
return null;
int compareResult = myCompare(x, t.data);
if(compareResult < 0){
t.left = remove(x, t.left);
//左节点被删除,需要考虑不平衡的情况有:RR、RL
if(height(t.right)-height(t.left) == 2){
TreeNode<T> r = t.right;
if(height(r.left) < height(r.right))
t = rotateWithRightChild(t);//右右情况
else
t = doubleWithRightChild(t);//右左情况
}
}else if(compareResult > 0){
t.right = remove(x, t.right);
//右节点被删除,需要考虑不平衡的情况有:LL、LR
if(height(t.left)-height(t.right) == 2){
TreeNode<T> r = t.left;
if(height(r.left) > height(r.right))
t = rotateWithLeftChild(t);//左左情况
else
t = doubleWithLeftChild(t);//左右情况
}
}else if(t.left != null && t.right != null){
//最小右节点替换不会造成不平衡
t.data = findMin(t.right).data;
t.right = remove(t.data, t.right);
}else{
t = (t.left != null)?t.left:t.right;
}

t.height = Math.max(height(t.left), height(t.right))+1;
return t;
}


2.7 完整代码

package com.demo10;

import java.util.Comparator;

public class AVLTreeDemo<T extends Comparable<? super T>> {

private TreeNode<T> root;
private Comparator<? super T> cmp;

/**
* 节点数据结构
* @author admin
* @param <T>
*/
public static class TreeNode<T>{
T data;
TreeNode<T> left;
TreeNode<T> right;
int height;

TreeNode(T data, TreeNode<T> lt, TreeNode<T> rt){
this.data= data;
this.left = lt;
this.right = rt;
this.height = 0;
}
}

/**
* 节点大小比较
* @param lhs
* @param rhs
* @return
*/
private int myCompare(T lhs, T rhs){
if(cmp != null)
return cmp.compare(lhs, rhs);
else
return ((Comparable)lhs).compareTo(rhs);
}

public void insert(T data){ root = insert(data, root); } /** * 插入节点,如果根节点不存在,则把待插入节点设为根节点 * @param x 待插入节点 * @param t 根节点 * @return */ private TreeNode<T> insert(T x, TreeNode<T> t){ if(t == null) return new TreeNode<T>(x, null, null); int compareResult = myCompare(x, t.data); if(compareResult < 0){//插入左子树 t.left = insert(x, t.left); if(height(t.left)-height(t.right) == 2){ if(myCompare(x, t.left.data) < 0) t = rotateWithLeftChild(t);//左左情况 else t = doubleWithLeftChild(t);//左右情况 } }else if(compareResult > 0){//插入右子树 t.right = insert(x, t.right); if(height(t.right)-height(t.left) == 2){ if(myCompare(x, t.right.data) < 0) t = doubleWithRightChild(t);//右左情况 else t = rotateWithRightChild(t);//右右情况 } } //更新height值 t.height = Math.max(height(t.left), height(t.right))+1; return t; }

/**
* 获取节点t高度
* @param t
* @return
*/
private int height(TreeNode<T> t){
return t == null ? -1 : t.height;
}

/** * 可将LL情况变平衡,也可将RL情况变成RR * @param k2 * @return */ private TreeNode<T> rotateWithLeftChild(TreeNode<T> k2){ TreeNode<T> k1 = k2.left; k2.left = k1.right; // 将RL情况变成RR 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; }

/** * 可将RR情况变平衡,也可将LR情况变成LL * @param k2 * @return */ private TreeNode<T> rotateWithRightChild(TreeNode<T> k2){ TreeNode<T> k1 = k2.right; k2.right = k1.left;//将LR情况变成LL 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; }

/** * 左右情况(LR)、双旋转 * 1、先右右再左左 * @param k3 * @return */ private TreeNode<T> doubleWithLeftChild(TreeNode<T> k3){ try{ k3.left = rotateWithRightChild(k3.left); }catch(NullPointerException e){ throw e; } return rotateWithLeftChild(k3); }
/** * 右左情况(RL),双旋转 * 1、先左左再右右 * @param k3 * @return */ private TreeNode<T> doubleWithRightChild(TreeNode<T> k3){ try{ k3.right = rotateWithLeftChild(k3.right); }catch(NullPointerException e){ throw e; } return rotateWithRightChild(k3); }

public void remove(T data){
root = remove(data, root);
}

/**
* 删除节点
* @param x
* @param t 根节点
* @return
*/
private TreeNode<T> remove(T x, TreeNode<T> t){
if(t == null)
return null;
int compareResult = myCompare(x, t.data);
if(compareResult < 0){
t.left = remove(x, t.left);
//左节点被删除,需要考虑不平衡的情况有:RR、RL
if(height(t.right)-height(t.left) == 2){
TreeNode<T> r = t.right;
if(height(r.left) < height(r.right))
t = rotateWithRightChild(t);//右右情况
else
t = doubleWithRightChild(t);//右左情况
}
}else if(compareResult > 0){
t.right = remove(x, t.right);
//右节点被删除,需要考虑不平衡的情况有:LL、LR
if(height(t.left)-height(t.right) == 2){
TreeNode<T> r = t.left;
if(height(r.left) > height(r.right))
t = rotateWithLeftChild(t);//左左情况
else
t = doubleWithLeftChild(t);//左右情况
}
}else if(t.left != null && t.right != null){
t.data = findMin(t.right).data;
t.right = remove(t.data, t.right);
}else{
t = (t.left != null)?t.left:t.right;
}

if(t!=null){
t.height = Math.max(height(t.left), height(t.right))+1;
}
return t;
}

private TreeNode<T> findMin(TreeNode<T> t){
if(t == null)
return null;
if(t.left == null)
return t;
return findMin(t.left);
}

private TreeNode<T> findMax(TreeNode<T> t){
if(t == null)
return null;
if(t.right == null)
return t;
return findMax(t.right);
}

/**
* 前序遍历
* @param tree
*/
private void preOrder(TreeNode<T> tree) {
if(tree != null) {
System.out.println(tree.data+" ");
preOrder(tree.left);
preOrder(tree.right);
}
}

public void preOrder() {
preOrder(root);
}

/**
* 中序遍历
* @param tree
*/
private void inOrder(TreeNode<T> tree) {
if(tree != null){
inOrder(tree.left);
System.out.println(tree.data+" ");
inOrder(tree.right);
}
}

public void inOrder() {
inOrder(root);
}

/**
* 后序遍历
* @param tree
*/
private void postOrder(TreeNode<T> tree) {
if(tree != null) {
postOrder(tree.left);
postOrder(tree.right);
System.out.println(tree.data+" ");
}
}

public void postOrder() {
postOrder(root);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息