JAVA数据结构与算法(七)java实现AVL树

JAVA数据结构与算法(七)java实现AVL树

1,AVL树又称平衡二叉树,它首先是一颗二叉查找树,但在二叉查找树中,某个结点的左右子树高度之差的绝对值可能会超过1,称之为不平衡。而在平衡二叉树中,任何结点的左右子树高度之差的绝对值会小于等于 1。

2,为什么需要AVL树呢?在二叉查找树中最坏情况下查找某个元素的时间复杂度为O(n),而AVL树能保证查找操作的时间复杂度总为O(logn)。

对于一棵BST树而言,不仅有查找操作,也有插入、删除等改变树的形态的操作。随着不断地插入、删除,BST树有可能会退化成链表的形式,使得查找的时间复杂度变成O(N),这种情形下,BST树的结构非常不平衡了。为了保持树的平衡,需要对树的形态做一些限制,因此,引入了AVL树,以保证树的左右子树高度之差的绝对值小于等于1。

如果一棵树非空,其任意一个节点的左右子树之间的高度差的绝对值不超过1(<=1),那么其就是平衡二叉树。
左右子树的高度差的绝对值称为平衡因子

// 对节点进行向左旋转操作,返回旋转后的根节点x
	//  y                    x
	// / \               /      \
	//T1  x           y            z
	//    / \ ----> /   \        / \
	//  T2   z       T1 T2       T3 T4
	//       / \
	//      T3 T4


 // 对节点进行向右旋转操作,返回旋转后的根节点x
	//       y                        x
	//      / \                   /      \
	//     x  T4               z          y
	//    / \   ---------->  / \      / \
	//   z  T3               T1 T2   T3 T4
	//  / \
	// T1 T2

AVL树的平衡保证算法
当向AVL树中插入或者删除元素时,可能打破树的平衡。这时,需要通过旋转来调整使之重新变成一颗AVL树。(这里讨论插入元素时的调整)
设 N 表示最接近新叶子的不平衡结点,由于插入元素之前树是平衡的,则插入之后不会有比 N 更高的不平衡结点。(树根的高度为 1 )
一共有 4 种原因导致结点 N 不平衡:
①在 结点 N 的左孩子的左子树中发生了插入操作(LL)
进行右旋转调整:即对结点 N 进行右旋转
②在 结点N 的右孩子的右子树中发生了插入操作(RR)
进行左旋转调整:即对结点N进行左旋转
③在 结点N 的右孩子的左子树中发生了插入操作(RL)
进行右-左旋转,即先对结点N 的孙子(孩子的孩子,“位于新插入元素的那个方向”)进行右旋转;再对结点N 的新孩子进行左旋转
④在 结点N 的左孩子的右子树中发生了插入操作(LR)
进行左-右旋转,即先对结点N的孙子进行左旋转,再对结点N的新孩子进行右旋转

public class AVLtree<K extends Comparable<K>,V> {

	class TreeNode{
		private K key;
		private V value;
		private TreeNode leftChild;
		private TreeNode rightChild;
		private TreeNode parent;
		private int height;
		
		public TreeNode(K key,V value){
			this.key=key;
			this.value=value;
			leftChild=null;
			rightChild=null;
			height=1;
		}
	}
	
	private TreeNode root;
	private int size;
	public AVLtree(){
	}
	//获得节点的高度
	public int getHeight(TreeNode node){
		if(node==null){
			return 0;
		}return node.height;
	}
	//获得节点的平衡因子
	public int getBanlaceFactor(TreeNode node){
		if(node==null){
			return 0;
		}
		return getHeight(node.leftChild)-getHeight(node.rightChild);
	}
	//判断二叉树是否为搜索二叉树
	 public boolean isBST(){
		 ArrayList<K> keys=new ArrayList<>();
		 inOrder(root, keys);
		 for(int i=1;i<keys.size();i++){
			 if(keys.get(i-1).compareTo(keys.get(i))>0){
				 return false;
			 }
		 }
		return false;
	 }
	 //判断是否是平衡二叉树
	 public boolean isBalanced(){
		 return isBalanced(root);
	 }
	 public boolean isBalanced(TreeNode node){
		 if(node==null){
			 return true;
		 }int balanceFactor=getBanlaceFactor(node);
		 if(Math.abs(balanceFactor)>1){
			 return false;
		 }return isBalanced(node.leftChild)&&isBalanced(node.rightChild);
	 }
	// 对节点进行向右旋转操作,返回旋转后的根节点x
		//       y                       x
		//      / \                  /     \
		//     x  T4               z          y
		//    / \   ----------> / \      / \
		//   z  T3              T1 T2 T3 T4
		//  / \
		// T1 T2
	 public TreeNode rightRotate(TreeNode y){
		 TreeNode x=y.leftChild;
		 TreeNode T3=x.rightChild;
		 //向右旋转过程
		 x.rightChild=y;
		 y.leftChild=T3;
		 //更新height(只更新x和y,先更新y)
		 y.height=Math.max(getHeight(y.leftChild), getHeight(y.rightChild)+1);
		 x.height=Math.max(getHeight(x.leftChild), getHeight(x.rightChild)+1);
		 return x;
	 }
	// 对节点进行向左旋转操作,返回旋转后的根节点x
		//  y                    x
		// / \               /      \
		//T1  x          y            z
		//    / \ ----> /   \        / \
		//  T2  z       T1 T2 T3 T4
		//        / \
		//      T3 T4
	 public TreeNode leftRotate(TreeNode y){
		TreeNode x=y.rightChild;
		TreeNode T2=x.leftChild;
		//向左旋转
		x.leftChild=y;
		y.rightChild=T2;
		//更新height
		 y.height=Math.max(getHeight(y.leftChild), getHeight(y.rightChild)+1);
		 x.height=Math.max(getHeight(x.leftChild), getHeight(x.rightChild)+1);
	     return x;
	 }
	 //返回以node为根的二分搜索树的最小值所在的节点
	 public TreeNode minimum(TreeNode node){
		 if(node.leftChild==null){
			 return node;
		 }return minimum(node.leftChild);
	 }
	 //删除以node为根的二分搜索树的最小节点
	 //返回删除节点后的新的二分搜索树的根
	 public TreeNode removeMin(TreeNode node){
		 if(node.leftChild==null){
			TreeNode rightNode=node.rightChild;
			 node.rightChild=null;
			 size--;
			 return rightNode;
		 }
		 node.leftChild=removeMin(node.leftChild);
		 return node;
	 }
	//添加
	 public TreeNode add(TreeNode node,K key,V value){
		 if(node==null){
			 size++;
			 return new TreeNode(key,value);
		 }
		 if(key.compareTo(node.key)<0){
			 node.leftChild=add(node.leftChild,key,value);
		 }else if(key.compareTo(node.key)>0){
			 node.rightChild=add(node.rightChild,key,value);
		 }else{
			 node.value=value;
		 }
		   //更新高度
		   node.height=1+Math.max(getHeight(node.leftChild), getHeight(node.rightChild));
		   //更新平衡因子
		   int balanceFactor=getBanlaceFactor(node);
		   if(Math.abs(balanceFactor)>1){
			   System.out.println("不是平衡二叉树"+balanceFactor);
		   }
		   //平衡维护
		   //LL
		   if(balanceFactor>1&&getBanlaceFactor(node.leftChild)>=0){
			    return rightRotate(node);
		   }
		   //RR
		    if(balanceFactor<-1&&getBanlaceFactor(node.leftChild)<=0){
			   return leftRotate(node);
		   }
		   //LR
		    if(balanceFactor>1&&getBanlaceFactor(node.leftChild)<0){
			   node.leftChild=leftRotate(node.leftChild);
			   return rightRotate(node);
		   }
		   //RL
		   if(balanceFactor<-1&&getBanlaceFactor(node.rightChild)>0){
			   node.rightChild=rightRotate(node.rightChild);
			   return leftRotate(node);
		   }
		return node;
	   }
	 //删除
	 public TreeNode remove(TreeNode node, K key){
		 if(node==null){
			 return null;
		 }
		 TreeNode retNode;
		 if(key.compareTo(node.key)<0){
			 node.leftChild=remove(node.leftChild, key);
			 retNode= node;
		 }
		 else if(key.compareTo(node.key)>0){
			 node.rightChild=remove(node.rightChild, key);
			 retNode= node;
		 }
		 else{  //key.compareTo(node.key)==0
			 //待删除节点左子树为空的情况
			 if(node.leftChild==null){
				 TreeNode rightNode=node.rightChild;
				 node.rightChild=null;
				 size--;
				 retNode= rightNode;
			 }
			 //待删除节点的右子树为空
			 else if(node.rightChild==null){
			 TreeNode leftNode=node.leftChild;
			 node.leftChild=null;
			 size--;
			 retNode= leftNode;
			 }
			 //待删除节点的左右子树不为空
			 
			 else{
				 TreeNode successor=minimum(node.leftChild);
			 successor.rightChild=remove(node.rightChild,successor.key);
			 successor.leftChild=node.leftChild;
			 
			 node.leftChild=node.rightChild=null;
			 retNode=successor;
			 } 
		 }
		 if(retNode==null){
			 return null;
		 }
		  //更新高度
		   retNode.height=1+Math.max(getHeight(retNode.leftChild), getHeight(retNode.rightChild));
		   //更新平衡因子
		   int balanceFactor=getBanlaceFactor(retNode);
		//   if(Math.abs(balanceFactor)>1){
			//   System.out.println("不是平衡二叉树"+balanceFactor);
		  // }
		 //平衡维护
		   //LL
		   if(balanceFactor>1&&getBanlaceFactor(retNode.leftChild)>=0){
			    return rightRotate(retNode);
		   }
		   //RR
		    if(balanceFactor<-1&&getBanlaceFactor(retNode.leftChild)<=0){
			   return leftRotate(retNode);
		   }
		   //LR
		    if(balanceFactor>1&&getBanlaceFactor(retNode.leftChild)<0){
		    	retNode.leftChild=leftRotate(retNode.leftChild);
			   return rightRotate(retNode);
		   }
		   //RL
		   if(balanceFactor<-1&&getBanlaceFactor(retNode.rightChild)>0){
			   retNode.rightChild=rightRotate(retNode.rightChild);
			   return leftRotate(retNode);
		   }
		return retNode;
	 }
		//中序
		public  void  inOrder(TreeNode head,ArrayList<K> keys){
			if(head==null){
				return;
			}
			inOrder(head.leftChild,keys);
			keys.add(head.key);
			inOrder(head.rightChild,keys);
		}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值