AVL树和Java实现
一.AVL树的特点
二.Java实现
三.增删改查时间复杂度
一.AVL树的特点
1.1 它是一种平衡二叉查找树的一种实现方式
1.2 任何节点的两个子树的高度差不超过1
由于上面的1.2特性,可知,它的做多节点数为一棵满树,最少节点数为斐波那契数列。
二.Java实现
理论可参照此文:http://www.cnblogs.com/skywang12345/p/3577479.html
package comUtils;
/**@description
* AVL树(平衡二叉查找树)基本类
* @author Jintao_Mat
* AVL树特点:
* 在二叉查找树的基础上任何节点的两个子树的高度最大差别为1。
* 注意:平衡二叉查找树不设置parent属性,因为涉及到旋转问题,parent会一直在变
*/
/**最多节点和最少节点的问题
* 最少节点为斐波那契数列
* 最多节点为一颗满树* */
public class BBSTree<T extends Comparable<T>>{
BBSNode<T> root; /*根节点*/
public class BBSNode<S extends Comparable<T>>{
S key; /*当前节点的值*/
BBSNode<S> left; /*左孩子*/
BBSNode<S> right; /*右孩子*/
int height;/*用于计算树的高度*/
public BBSNode(S key, BBSTree<T>.BBSNode<S> left,
BBSTree<T>.BBSNode<S> right, int height) {
super();
this.key = key;
this.left = left;
this.right = right;
this.height = height;
}
@Override
public String toString() {
return "BBSNode [key=" + key + ", left=" + left + ", right="
+ right + ", height=" + height + "]";
}
}
/*基本方法*/
private boolean isNull(BBSNode<T> bSNode){
return null == bSNode;
}
private boolean isNotNull(BBSNode<T> bSNode){
return !isNull(bSNode);
}
/**@description
* 判断树是否为空
*/
public boolean isEmpty(){
return isNull(root);
}
/**@description
* 平衡二叉树构造函数
*/
public BBSTree() {
}
/**@description
* 初始化平衡二叉树
*/
public void init(){
root = null;
}
/**@description
* 判断节点是不是根节点
*/
public boolean isRoot(BBSNode<T> bSNode){
return (root == bSNode)? true:false;
}
/**@description
* 前序遍历
*/
public void beforeFind(BBSNode<T> treeNode){
if(isNotNull(treeNode)){
System.out.print(treeNode.key+" ");
beforeFind(treeNode.left);
beforeFind(treeNode.right);
}else{
}
}
public void beforeFind(){
beforeFind(root);
}
/**@description
* 中序遍历
*/
public void middleFind(BBSNode<T> treeNode){
if(isNotNull(treeNode)){
middleFind(treeNode.left);
System.out.print(treeNode.key+" ");
middleFind(treeNode.right);
}else{
}
}
public void middleFind(){
middleFind(root);
}
/**@description
* 后序遍历
*/
public void afterFind(BBSNode<T> treeNode){
if(isNotNull(treeNode)){
afterFind(treeNode.left);
afterFind(treeNode.right);
System.out.print(treeNode.key+" ");
}else{
}
}
public void afterFind(){
afterFind(root);
}
/**@description
* 更新一个节点的高度
*/
private int updateHeight(BBSNode<T> bBSNode){
int left = 0,right = 0;
if(isNotNull(bBSNode.left)){
left = bBSNode.left.height;
}
if(isNotNull(bBSNode.right)){
right = bBSNode.right.height;
}
return bBSNode.height = left>right? left:right;
}
/**@description
* 增加一个节点的高度
*/
private int addHeight(BBSNode<T> bBSNode){
int left = 0,right = 0;
if(isNotNull(bBSNode.left)){
left = bBSNode.left.height;
}
if(isNotNull(bBSNode.right)){
right = bBSNode.right.height;
}
return bBSNode.height = left>right? left+1:right+1;
}
/**@description
* 减少一个节点的高度
*/
private int delHeight(BBSNode<T> bBSNode){
int left = 0,right = 0;
if(isNotNull(bBSNode.left)){
left = bBSNode.left.height;
}
if(isNotNull(bBSNode.right)){
right = bBSNode.right.height;
}
return bBSNode.height = left>right? left-1:right-1;
}
/**@description
* 判断一个节点是否平衡
*/
public boolean isBanNode(BBSNode<T> bBSNode){
int leftHeight = -1;/*任何一个节点的高度差为0,而不确定这个节点是否存在时,设置其高度差为-1*/
int rightHeight = -1;
leftHeight = isNull(bBSNode.left)? leftHeight:bBSNode.left.height;
rightHeight = isNull(bBSNode.right)? rightHeight:bBSNode.right.height;
return (leftHeight-rightHeight<=1 && rightHeight-leftHeight<=1)? true:false;
}
/**@description
* 左左旋转:插入或删除一个节点后,根节点的左子树的左子树还有非空子节点
*/
private BBSNode<T> LLRotate(BBSNode<T> bBSNode){
/*bBSNode和LNode是为了计算高度时使用*/
BBSNode<T> LNode = bBSNode.left;
bBSNode.left = LNode.right;
LNode.right = bBSNode;
/*旋转之后更新树的高度*/
updateHeight(bBSNode);
updateHeight(LNode);
return LNode;
}
/**@description
* 右左旋转(旋转两次)
*/
private BBSNode<T> RLRotate(BBSNode<T> bBSNode){
/*先左左旋转,再右右旋转*/
bBSNode.right = LLRotate(bBSNode.right);
return RRRotate(bBSNode);
}
/**@description
* 左右旋转(旋转两次) 插入或删除一个节点后,根节点的左子树的右子树还有非空子节点
*/
private BBSNode<T> LRRotate(BBSNode<T> bBSNode){
/*先右右旋转,再左左旋转*/
bBSNode.left = RRRotate(bBSNode.left);
return LLRotate(bBSNode);
}
/**@description
* 右右旋转:插入或删除一个节点后,根节点的右子树的右子树还有非空子节点
*/
private BBSNode<T> RRRotate(BBSNode<T> bBSNode){
/*bBSNode和LNode是为了计算高度时使用*/
BBSNode<T> LNode = bBSNode.right;
bBSNode.right = LNode.left;
LNode.left = bBSNode;
/*旋转之后更新树的高度*/
updateHeight(bBSNode);
updateHeight(LNode);
return LNode;
}
/**@description
* 添加值的时候
* 1.更新每个上级节点的高度
* 2.判断所有节点是否平衡
* 3.如果不平衡,如何进行旋转
*/
public BBSNode<T> insert(BBSNode<T> root,BBSNode<T> bBSNode){
if(bBSNode.key.compareTo(root.key) < 0){
if(isNotNull(root.left)){
root.left = insert(root.left,bBSNode);
if(!isBanNode(root)){/*树不平衡,说明可能是LL或者LR的情形*/
if(bBSNode.key.compareTo(root.left.key) < 0){ /*LL的情形*/
/*左左旋转*/
root = LLRotate(root);
}else{ /*LR的情形*/
root = LRRotate(root);
System.out.println(root.height);
if(isNotNull(root.left))
System.out.println(root.left.height);
if(isNotNull(root.right))
System.out.println(root.right.height);
}
}else{
}
}else{
root.left = bBSNode;
addHeight(root);
}
}else if(bBSNode.key.compareTo(root.key) > 0){
if(isNotNull(root.right)){
root.right = insert(root.right,bBSNode);
if(!isBanNode(root)){/*树不平衡,说明可能是LL或者LR的情形*/
if(bBSNode.key.compareTo(root.right.key) > 0){ /*RR的情形*/
/*右右旋转*/
root = RRRotate(root);
}else{ /*RL的情形*/
root = RLRotate(root);
}
}else{
}
}else{
root.right = bBSNode;
addHeight(root);
}
}else{
/*值相等什么也不做*/
return root;
}
updateHeight(root);
return root;
}
/**@description
* 添加值
*/
public void addBBSNode(T key){
BBSNode<T> bBSNode = new BBSNode<T>(key, null, null, 0);
if(isEmpty()){
root = bBSNode;
}else{
root = insert(root,bBSNode);
}
}
/**@description
* 删除节点,如果不破坏树的结构(中序遍历是递增的)
* 1.判断删除的是左子树还是右子树
* 2.如果正好是这个节点
* 1)需要删除的节点下并没有其他子节点
* 2)需要删除的节点下有一个子节点(左或者右)
* 3)需要删除的节点下有两个子节点(通过查找它的前驱节点(后继节点),然后替换该节点,最后删除前驱节点(后继节点))
*/
private BBSNode<T> delBSNode(BBSNode<T> root, T key){
if(isNull(root)){
return null;
}
if(key.compareTo(root.key) < 0){ /*删除左子树*/
root.left = delBSNode(root.left,key);
if(!isBanNode(root)){/*树不平衡,说明可能是LL或者LR的情形*/
if((isNotNull(root.right.left)? root.right.left.height:-1) > (isNotNull(root.right.right)? root.right.right.height:-1)){ /*LL的情形*/
/*右左旋转*/
root = RLRotate(root);
}else{ /*右右的情形*/
root = RRRotate(root);
}
}else{
}
}else if(key.compareTo(root.key)> 0){ /*删除右子树*/
root.right = delBSNode(root.right,key);
if(!isBanNode(root)){/*树不平衡,说明可能是LL或者LR的情形*/
if((isNotNull(root.right.left)? root.right.left.height:-1) > (isNotNull(root.right.right)? root.right.right.height:-1)){ /*LL的情形*/
/*左左旋转*/
root = LLRotate(root);
}else{ /*左右的情形*/
root = LRRotate(root);
}
}else{
}
}else{/*删除的正是该节点*/
if(isNull(root.left) && isNull(root.right)){
return null;
}else if(isNull(root.left) || isNull(root.right)){
root = (isNotNull(root.left))? root.left:root.right;
/*减去它的高度*/
delHeight(root);
}else{/*有两个孩子,根据该节点的左右孩子的高度来判断使用前驱节点或后继节点来替换,从而不影响该节点的平衡*/
if(root.left.height > root.right.height){ /*找前驱节点*/
BBSNode<T> maxNode = MaxBode(root.left);
SwitchKey(maxNode,root);
root.left = delBSNode(root.left,maxNode.key);
}else{ /*找后继节点*/
BBSNode<T> minNode = MinBode(root.right);
SwitchKey(minNode,root);
root.right = delBSNode(root.right,minNode.key);
}
}
}
updateHeight(root);
return root;
}
public BBSNode<T> delBSNode(T key){
root = delBSNode(root,key);
return root;
}
/**@description
* 查找树(右子树)中的最小节点 即后继节点
* @return
* BSNode<T>
*/
public BBSNode<T> MinBode(BBSNode<T> tree){
if(isNotNull(tree)){
if(isNotNull(tree.left)){
return MaxBode(tree.left);
}else{
return tree;
}
}else{
return null;
}
}
/**@description
* 查找树(左子树)中的最大节点 即前驱节点
* @return
* BSNode<T>
*/
public BBSNode<T> MaxBode(BBSNode<T> tree){
if(isNotNull(tree)){
if(isNotNull(tree.right)){
return MaxBode(tree.right);
}else{
return tree;
}
}else{
return null;
}
}
/**@description
* 交换两个Node的值
*/
public void SwitchKey(BBSNode<T> A,BBSNode<T> B){
T key;
key = A.key;
A.key = B.key;
B.key = key;
}
/**@description
* 返回key所在的节点(中序查找所有节点)
*/
public BBSNode<T> findAllNode(T key){
return isNull(root)? null:middleFindByKey(root,key);
}
public BBSNode<T> middleFindByKey(BBSNode<T> treeNode,T key){
BBSNode<T> bBSNode = null;
/*优先查找左自树*/
if(isNotNull(treeNode.left)){
bBSNode = middleFindByKey(treeNode.left,key);
if(isNotNull(bBSNode)){
return bBSNode;
}
}else{
}
/*查找中间节点*/
if(0 == treeNode.key.compareTo(key)){
return bBSNode = treeNode;
}else{
}
/*查找右子树*/
if(isNotNull(treeNode.right)){
bBSNode = middleFindByKey(treeNode.right,key);
if(isNotNull(bBSNode)){
return bBSNode;
}
}else{
}
return bBSNode;
}
public static void main(String[] args) {
BBSTree<Integer> bBSTree = new BBSTree<Integer>();
/*新增数据*/
bBSTree.addBBSNode(new Integer(40));
bBSTree.addBBSNode(new Integer(20));
bBSTree.addBBSNode(new Integer(60));
bBSTree.addBBSNode(new Integer(50));
bBSTree.addBBSNode(new Integer(70));
bBSTree.addBBSNode(new Integer(45));
bBSTree.addBBSNode(new Integer(7));
bBSTree.addBBSNode(new Integer(8));
/*删除数据*/
bBSTree.delBSNode(7);
bBSTree.delBSNode(8);
bBSTree.delBSNode(40);
bBSTree.delBSNode(20);
bBSTree.delBSNode(60);
// bBSTree.delBSNode(50);
// bBSTree.delBSNode(70);
// bBSTree.delBSNode(45);
bBSTree.middleFind();
System.out.println();
bBSTree.beforeFind();
System.out.println();
bBSTree.afterFind();
}
}
三.增删改查的时间复杂度
增删改查的时间复杂度都是LogN, 只是每次增加或者删除节点都会重新旋转以达到高度平衡。由于是高度平衡的二叉树,因此随机的情况下,查改的时间复杂度是树中最快的。