AVL树的定义:带有平衡条件的二叉查找树,其左右子树的高度差小于等于1。通过对树的旋转保持平衡。
本文是通过保存高度值实现删除和插入
准备工作
public class AvlTree<T extends Comparable<? super T>> {
//保存根节点
private AvlNode<T> root;
//定义节点
private static class AvlNode<T>{
AvlNode<T> left;//左儿子
AvlNode<T> right;//右儿子
T data;//数据域
int height;//高度
public AvlNode(T data){
this(data,null,null);
}
public AvlNode(T d,AvlNode<T> l,AvlNode<T> r){
left=l;
right=r;
data=d;
height=0;
}
}
public AvlTree(){
clear();
}
private int height(AvlNode<T> t){
return t==null?-1:t.height;
}
public boolean isEmpty(){
return root==null;
}
public void insert(T data){
root=insert(root,data);
}
public int getHeight(){
return height(root);
}
public void clear(){
root=null;
}
public void remove(T data){
root=remove(root,data);
}
public T findMin(){
return findMin(root).data;
}
public void printTree(){
printTree(root);
}
private void printTree(AvlNode<T> t){
if(t==null)
return;
printTree(t.left);
System.out.println(t.data);
printTree(t.right);
}
private AvlNode<T> findMin(AvlNode<T> t){
if(isEmpty()){
return null;
}
if(t.left==null)
return t;
else
return findMin(t.left);
}
//右双旋转
private AvlNode<T> doubleWithRightChild(AvlNode<T> k3) {
k3.right=rotateWithLeftChild(k3.right);
return rotateWithRightChild(k3);
}
//右单旋转
private AvlNode<T> rotateWithRightChild(AvlNode<T> k2) {
AvlNode<T> k1 = k2.right;
k2.right=k1.left;
k1.left=k2;
k2.height=Math.max(height(k2.left), height(k2.right))+1;
k1.height=Math.max(height(k1.left), height(k1.right))+1;
return k1;
}
//双旋转其实就是两次的单旋转
private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3) {
k3.left=rotateWithRightChild(k3.left);
return rotateWithLeftChild(k3);
}
//左单旋转
private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2) {
AvlNode<T> k1 = k2.left;
k2.left=k1.right;
k1.right=k2;
k2.height=Math.max(height(k2.left), height(k2.right))+1;
k1.height=Math.max(height(k1.left), height(k1.right))+1;
return k1;
}
- 插入
private AvlNode<T> insert(AvlNode<T> t, T data) {
if(t==null){
return new AvlNode<T>(data);
}
int comparaResult =data.compareTo(t.data);
if(comparaResult<0){
t.left=insert(t.left,data);
if(height(t.left)-height(t.right)==2){//不平衡条件
if(data.compareTo(t.left.data)<0){
t=rotateWithLeftChild(t);
}else{
t=doubleWithLeftChild(t);
}
}
}
else if(comparaResult>0){
t.right=insert(t.right,data);
if(height(t.right)-height(t.left)==2){
if(data.compareTo(t.right.data)>0){
t=rotateWithRightChild(t);
}else{
t=doubleWithRightChild(t);
}
}
}
else
;//重复的值,直接返回。
t.height=Math.max(height(t.left), height(t.right))+1;
return t;
}
2.删除:如果删除并不是非常频繁,采用惰性删除是最好的方式。本文没有采用这样的策略。
private AvlNode<T> remove(AvlNode<T> t,T data){
if(t==null)
return t;//没有找到
int compareResult = data.compareTo(t.data);
if(compareResult<0){//往左走
t.left=remove(t.left,data);
//在左子树中删除后该节点失衡,若失衡,则可以肯定的是该节点的右子树比左子树高
if (height(t.right) - height(t.left) == 2) {
//一字型失衡,单旋转
if (height(t.right.right)>=height(t.right.left)) {
t = rotateWithRightChild(t);
} else {//之字形失衡,双旋转
t = doubleWithRightChild(t);
}
}
}else if(compareResult>0){//往右走
t.right=remove(t.right,data);
if (height(t.left) - height(t.right) == 2 ) {
if(t.left!=null){
if (height(t.left.left)>=height(t.left.right)) {
t = rotateWithLeftChild(t);
} else {
t = doubleWithLeftChild(t);
}
}
}
//找到了要删除的节点,该节点左右子树都不为空
}else if(t.left!=null&&t.right!=null){
//特殊情况,当右子树的最小节点就是右儿子并且右儿子的右子树为空
boolean iooo=(t.right==findMin(t.right)&&t.right.right==null);//判定结果
t.data=findMin(t.right).data;//用右子树的最小节点替换该节点
t.right=remove(t.right,t.data);//删除右子树的最小节点
if(iooo){//特殊情况成立,则节点已经失衡,左单旋转
t=rotateWithLeftChild(t);
}
}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;
}