平衡二叉树 AVL树 双旋转

问题 若数组{1,2,3,4,5,6}组成二叉排序树 整棵树左子节点全为空 则相当于链表 而在实际操作中如增删查 效率还会更低 为了避免这种情况发生 需要对二叉排序树旋转 使左右子树高度差不超过1
基本介绍

  1. 平衡二叉树也叫平衡二叉搜索树(Self balancing binarysearch tree) 又被称为
    AVL树,可以保证查询效率较高。
  2. 具有以下特点:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、 伸展树等。

左旋
问题:当插入8时
rightHeight()- leftHeight()>1成立,此时,不再是一颗avl树了.
怎么处理- -进行左旋转.
1.创建一个新的节点newNode (以4这个值创建),创建一个新的节点,值等于当前根节点的值
//把新节点的左子树设置了当前节点的左子树
2. newNode.left = left
//把新节点的右子树设置为当前节点的右子树的左子树
3. newNode.right =right.left;
//把当前节点的值换为右子节点的值
4.value=right.value;
//把当前节点的右子树设置成右子树的右子树
5. right=right.right;
//把当前节点的左子树设置为新节点
6. left=newLeft;
在这里插入图片描述在这里插入图片描述
右旋转
问题:当插入6时
leftHeight) -rightHeight() >1成立,此时,不再是一颗av树 了
怎么处理-进行右旋转.(就是降低左子树的高度,这里是将9这个节点,通过右旋转,到右子树
1.创建一-个新的节点newNode(以10这个值创建),创建一个新的节点,值等于当前根节点的值
//把新节点的右子树设置了当前节点的右子树
2. newNode.right = right
//把新节点的左子树设置为当前节点的左子树的右子树
3. newNode.left =leftright;
///把当前节点的值换为左子节点的值
4.value-left.value;
//把当前节点的左子树设置成左子树的左子树
5. left=left.left;
//把当前节点的右子树设置为新节点
6. right=newLeft;
在这里插入图片描述在这里插入图片描述

双旋转
前面的两个数列,进行单旋转(即一次旋转)就可以将非平衡二叉树转成平衡二叉树,
但是在某些情况下,单旋转不能完成平衡二叉树的转换。比如数列
int[]arr={10,11,7,6,8,9}; 运行原来的代码可以看到,并没有转成AVL树.
int[] arr = {2,1,6,5,7,3}; //运行原来的代码可以看到,并没有转成AVL树
处理方法
1.当符合右旋转的条件时
2.如果它的左子树的右子树高度大于它的左子树的高度
3.先对当前这个结点的左节点进行左旋转
4.在对当前结点进行右旋转的操作即可


public class AVLTreeDemp {

	public static void main(String[] args) {
//		int[] arr = {4,3,6,5,7,8};
		//int[] arr = {10,12,8,9,7,6};
		int[] arr = {10,11,8,9,7,6};
		AVLTree avlTree = new AVLTree();
		//添加节点
		for(int i=0;i<arr.length;i++) {
			avlTree.add(new Node(arr[i]));
		}
		//遍历
		System.out.println("中序遍历");
		avlTree.infixOrder();
		System.out.println("平衡旋转");
		System.out.println(avlTree.getRoot().height());//4
		System.out.println(avlTree.getRoot().leftHeight());//1
		System.out.println(avlTree.getRoot().rightHeight());//3
		System.out.println(avlTree.getRoot());
		System.out.println(avlTree.getRoot().left);
	}

}
//创建avlTree
class AVLTree{
	private Node root;
	
	public Node getRoot() {
		return root;
	}
	
	//添加节点
	public void add(Node node) {
		if(root == null) {
			root = node;
		}else {
			root.add(node);
		}
	}
	//中序遍历
	public void infixOrder() {
		if(root != null) {
			root.infixOrder();
			
		}else {
			System.out.println("树为空 无法遍历");
		}
	}
	//查找要删除的节点
	public Node search(int value) {
		if(root == null) {
			return null;
		}else {
			return root.search(value);
		}
	}
	//查找要删除节点的父节点
	public Node searchParent(int value) {
		if(root == null) {
			return null;
		}else {
			return root.searchParent(value);
		}
	}
	
	//node 传入的节点(当做二叉排序树的根节点)
	//返回该二叉排序树的最小节点的值 并删除该值
	public int delRightTree(Node node) {
		Node target = node;
		//循环查找右子树的左节点 找到最小值
		while(target.left != null) {
			target = target.left;
		}
		//这是target指向最小节点 删除
		delNode(target.value);
		return target.value;
		
	}
	
	//删除节点
	public void delNode(int value) {
		if(root == null) {
			return;
		}
		//	要删除的节点
		Node targetNode = search(value);
		if(targetNode == null) {
			return ;
		}
		if(root.left == null &&root.right == null) {
			//只有一个节点	
			root = null;
			return;
		}
		Node parent = searchParent(value);
		if(targetNode.left == null && targetNode.right == null ) {
			//节点为叶子结点
			//判断targetNode是其父节点的左子节点还是右子节点
			if(parent.left != null && parent.left.value == value) {
				parent.left = null;
			} else if(parent.right != null && parent.right.value == value) {
				parent.right = null;
			}
		}else if(targetNode.left != null && targetNode.right != null) {
			//有两个子树节点的节点
			int minVal = delRightTree(targetNode.right);
			targetNode.value = minVal;
		} else {
			// 删除只有一颗子树的节点
			if (targetNode.left != null) {
				if (parent != null) {// 非根节点
					// 有左子节点
					if (parent.left.value == value) {
						// 是左子节点
						parent.left = targetNode.left;
					} else {
						// 是右子节点
						parent.right = targetNode.left;
					}
				} else {
					root = targetNode.left;
				}
			} // 有右子节点
			else {
				if (targetNode.right != null) {
					if (parent.left.value == value) {
						// 是左子节点
						parent.left = targetNode.right;
					} else {
						// 是右子节点
						parent.right = targetNode.right;
					}
				} else {
					root = targetNode.right;
				}
			}
		}
	}
}
//节点
class Node{
	int value;
	Node left;
	Node right;
	public Node(int value) {
		this.value = value;
	}
	
	public String toString() {
		return "Node [value=" + value + "]";
	}

	//添加节点
	//递归 需要满足二叉排序树
	public void add(Node node) {
		if(node == null) {
			return;
		}else {
		//判断传入的节点的值 和当前子树的根节点的关系
			if(node.value < this.value) {
				if(this.left == null) {
					this.left = node;
				}else {
					this.left.add(node);//递归找到位置
				}
			}else {
					if(this.right == null) {
						this.right = node;
					}else {
						this.right.add(node);//递归找到位置
					}
				}
			}
		//当 添加完一个节点后 如果右子树高度-左子树高度大于1 需要左旋转
		if(rightHeight() - leftHeight() > 1) {
			if(right != null && right.rightHeight()<right.leftHeight()) {
				//当前节点 右子树的左子树的高度大于右子树的右子树高度
				//先对其先进行右旋转
				right.rightRotate();
				}
			leftRotate();
		}
		//右旋转
		if(leftHeight() - rightHeight() > 1) {
			//若根节点的左子树的右子树大于其左子树的左子树
			if(left != null && left.rightHeight()>left.leftHeight()) {
				//先对其先进行左旋转
				left.leftRotate();
			}
			rightRotate();
		}
		return;//不需要继续判断
	}
	//中序遍历
	public void infixOrder() {
		if(this.left != null) {
			this.left.infixOrder();
		}
		System.out.println(this);
		if(this.right != null) {
			this.right.infixOrder();
		}
	}
	//查找要删除的节点
	public Node search(int value) {
		if(value == this.value) {
			//找到就是该节点
			return this;
		}else if(value < this.value){
			//如果查找到的值小于当前节点的值 则向左子树找
			//若左子节点为空则不能继续查找
			if(this.left == null) {
				return null;
			}
			return this.left.search(value);
		}else {
			//如果查找到的值大于当前节点的值 则向右子树找
			if(this.right == null) {
				return null;
			}
			return this.right.search(value);
		}
	}
	//查找要删除节点的父节点
	public Node searchParent(int value) {
		if((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) {
			return this;//当前节点为要删除节点的父节点
		}else {
			if(value < this.value && this.left != null){
				//如果查找到的值小于当前节点的值 则向左子树找
				//若左子节点为空则不能继续查找
				return this.left.searchParent(value);
			}
			else if(value >= this.value && this.right != null){
				//如果查找到的值大于当前节点的值 则向右子树找
				//若右子节点为空则不能继续查找
				return this.right.searchParent(value);
			}else {
				//无父节点 
				return null;
			}
		}
		
	}
	//返回左子树的高度
	public int leftHeight() {
		if(left == null) {
			return 0;
		}
		return left.height();
	}
	//返回右子树的高度
		public int rightHeight() {
			if(right == null) {
				return 0;
			}
			return right.height();
		}
	//返回当前节点的高度(已该节点为根节点的树的高度)
	public int height() {
		return Math.max(left == null ? 0:left.height(),right == null ? 0 : right.height())+1;
	}
	//左旋转
	private void leftRotate() {
		//创建新的节点 以当前根节点的值
		Node newNode = new Node(value);
		//把新的节点的左子树设置成当前节点的左子树(左子树等于不变)
		newNode.left = left;
		//把新节点的右子树设置成当前节点的右子树的左子树
		newNode.right = right.left;
		//把当前节点的值换成右子节点的值
		value = right.value;
		//把当前节点的右子树设置成当前节点右子树的的右子树
		right = right.right;
		//把当前节点的左子节点设置成新的节点
		left = newNode;
	}
	//右旋转
	private void rightRotate() {
		Node newNode = new Node(value);
		newNode.right = right;
		newNode.left = left.right;
		value = left.value;
		left = left.left;
		right = newNode;
	}
}
	


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值