二叉平衡树

二叉平衡树

说起这个树,我找了整整两天的时间,刚开始考虑的不周全,然后就一直该一直该,一直加一直加。
定义:
它是一颗空疏或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。
二叉查找树的定义:
1、若左子树不为空,那么左子树所有结点的值小于均小于他的根结点的值
2、若右子树不为空,那么右子树的所有结点的值大于根结点的值
3、左右子树也分别为二叉查找树(排序树)
4、没有键值相当的结点
如果不知道二叉查找树了请看我上篇文章(格式不太好)
现在二叉查找树添加的源码:
在这里我定义了root,opRoot两个,root主要是根结点,方便以后去操作,opRoot主要是操作树的。

// 插入元素
	public void insert(T t){
		if(opRoot == null){
			root.setT(t);
			opRoot = root;
			return ;
		}
		opRoot = root ;
		Node<T> node = new Node<T>();
		node.setT(t);
		insert(opRoot , node) ;
	}
	// 插入值
	private void insert(Node<T> opRoot, Node<T> node) {
		if(opRoot.getT().compareTo(node.getT()) > 0){
			if(opRoot.getLeft() != null){
				insert(opRoot.getLeft() , node ) ;
			}else {
				opRoot.setLeft(node);
				node.setParent(opRoot);
			}
		}
		if(opRoot.getT().compareTo(node.getT()) < 0){
			if(opRoot.getRight() != null){
				insert(opRoot.getRight() , node) ;
			}else {
				opRoot.setRight(node);
				node.setParent(opRoot);
			}
		}
	}

值已经插进去了,现在我们要判断这四种情况:
1、 在结点x的左孩子的左子树中插入元素(左左)
2、 在结点x的左孩子的右子树中插入元素(左右)
3、 在结点x的右孩子的左子树中插入元素(右左)
4、 在结点x的右孩子的右子树中插入元素(右右)
括号里这些代表有,没写的代表下层没有
首先看第一种情况:
这里写图片描述
我是这样考虑的,换位置,把第一个左换到上面,然后把第一个上面的放到有下面,注意:需要断开的一定要断开。
第四种情况,有类似第一种:
这里写图片描述
类似于上面那种,也是交换位置
还有一个leftOrRight这个类
这里写图片描述

这里是段开父类之后,然后下面的那个元素指向父类元素
第二种左右,也是交换位置
这里写图片描述
把最上面的和最下面的交换位置就行,把4放到5的位置,把5放到4的右子树
这里写图片描述
第三种右左

这里写图片描述
这里写图片描述
把四和三交换位置,然后把3放到4的左子树
最后一个root.setParent(null),防止操作到根元素,忘记把根的父给清除了。
这里写图片描述
上面这段代码也是判断父类的到底该左子树设置还是右子树设置。
接下来,还要考虑这种:
这里写图片描述
左边是第一次按照上面那样插入,留下的病根,右边左转一次的情况,这里还有右转,直到达到预期效
下面代码弄了好多次都不型,只能这样了,作用是判断左右的深度差师傅大于1.

private void leftAndRightBalance(Node<T> opRoot) {
	int left = treeDepth(opRoot.getLeft()) ;
	int right = treeDepth(opRoot.getRight()) ;
	if(left - right > 1){
		rightxuanzhuan(opRoot);
		return ;
	}
	if(right - left > 1){
		leftxuanzhuan(opRoot);
		return ;
	} 
底下是右旋转旋转一次
// 这里是左旋转的
private void rightxuanzhuan(Node<T> opRoot) {
	Node<T> parent = opRoot.getParent();
	Node<T> left = opRoot.getLeft();
	Node<T> right = opRoot.getRight();
	Node<T> rightLeft = findLeft(right);
	if(rightLeft.getT().compareTo(right.getT()) == 0){
		rightLeft = null ;
	}
	newxuanzhuan(rightLeft);
	left.setParent(parent);
	if(parent != null){
		parent.setLeft(left);
	}else {
		root = left ;
		left.setParent(null);
	}
	if(rightLeft != null){
		rightLeft.setLeft(left.getLeft());
	}
	if(left.getLeft()!=null){
		left.getLeft().setParent(rightLeft);
	}
	}else{
		opRoot.setLeft(left.getRight());
		if(left.getRight() != null){
		left.getRight().setParent(opRoot);
	}
	left.setRight(opRoot);
	zaipanduan(left)
}
	
左旋转一次
private void leftxuanzhuan(Node<T> opRoot) {
	Node<T> parent = opRoot.getParent();
	Node<T> right = opRoot.getRight();
	Node<T> rightleft = findLeft(right);
	newxuanzhuan(rightleft);
	right.setParent(parent);
	if(parent != null){
		parent.setRight(right);
	}else{
		root = right;
	}
	if(rightleft != null){
		rightleft.setLeft(opRoot);
		opRoot.setParent(rightleft);
	}else{
		right.setLeft(opRoot);
		opRoot.setParent(right);
	}
	opRoot.setRight(null);
	zaipanduan(right);
} 
// 为上面这两个类提供的旋转
	private void newxuanzhuan(Node<T> rightleft) {
		if(rightleft == null){
			return ;
		}
		Node<T> parent = rightleft.getParent();
		if(parent == null || parent.getRight() != null){
			return ;
		}
		rightleft.setParent(parent.getParent());
		
	if(parent.getParent().getLeft() != null && parent.getParent().getLeft().getT().compareTo(parent.getT()) == 0){
			parent.getParent().setLeft(parent.getLeft());
		}else{
			parent.getParent().setRight(parent.getLeft());
		}
		rightleft.setRight(parent);
		parent.setParent(rightleft);
		parent.setLeft(null);
	}
作用是为上面两个方法提供旋转

下面这个是再进去,判断是否合理
private void zaipanduan(Node<T> left) {
		if(left != null && left.getLeft() != null){
			zaipanduan(left.getLeft());
		}
		if(left !=null && left.getRight() != null){
			zaipanduan(left.getRight());
		}
		zaipanduandigui(left);
	}
	private void zaipanduandigui(Node<T> left){
		xuanzhuanshu(left);
	}

接下来给你们源码看,在这我建议你一步一步来,每一种你考虑考虑,然后把代码进一步优化
public void insert(T t) {
		if (root.getT() == null) {
			root.setT(t);
			size++;
			return;
		}
		opRoot = root;
		Node<T> node = new Node<T>();
		node.setT(t);
		insert(opRoot, node);
		size++;
	}

	private void insert(Node<T> opRoot, Node<T> node) {

		if (opRoot.getT().compareTo(node.getT()) > 0) {
			if (opRoot.getLeft() != null) {
				insert(opRoot.getLeft(), node);
			} else {
				opRoot.setLeft(node);
				node.setParent(opRoot);
				xuanzhuanshu(node);
			}
		}
		if (opRoot.getT().compareTo(node.getT()) < 0) {
			if (opRoot.getRight() != null) {
				insert(opRoot.getRight(), node);
			} else {
				opRoot.setRight(node);
				node.setParent(opRoot);
				xuanzhuanshu(node);
			}
		}
	}

	/*
	 * 添加的时候有四种判断方式。 第一种是左左 第二种是右右 第三种是左右 第四种是右左
	 */
	private void xuanzhuanshu(Node<T> node) {
		Node<T> parent = null;
		// 判断,是否右父父(爷爷元素)
		if (node.getParent() != null && node.getParent().getParent() != null)
			parent = node.getParent().getParent();
		if (parent == null) {
			return;
		}
		// 连续左左为空,右右有元素
		if (parent.getLeft() == null && node.getParent().getLeft() == null) {
			if (parent.getParent() != null) {
				leftOrRight(parent.getParent(), node.getParent());
				node.getParent().setParent(parent.getParent());
				node.getParent().setLeft(parent);
			} else {
				node.getParent().setLeft(parent);
				root = node.getParent();
			}
			parent.setParent(node.getParent());
			parent.setRight(null);
		}
		// 连续左左有元素,右右为空
		if (parent.getRight() == null && node.getParent().getRight() == null) {
			if (parent.getParent() != null) {
				leftOrRight(parent.getParent(), node.getParent());
				node.getParent().setParent(parent.getParent());
				node.getParent().setRight(parent);
			} else {
				node.getParent().setRight(parent);
				root = node.getParent();
			}
			parent.setParent(node.getParent());
			parent.setLeft(null);
		}
		// 下面是右空,然后在左空
		if (parent.getRight() == null && node.getParent().getLeft() == null) {
			if (parent.getParent() != null) {
				leftOrRightNoOnOne(parent.getParent(), node);
				node.setParent(parent.getParent());
				node.setLeft(parent.getLeft());
				parent.getLeft().setParent(node);
				parent.getLeft().setRight(null);
				node.setRight(parent);
				parent.setParent(node);
				parent.setLeft(null);
			} else {
				root = node;
				node.setRight(parent);
				parent.setParent(node);
				parent.setLeft(null);
				node.setLeft(node.getParent());
				node.getParent().setParent(node);
				node.getParent().setRight(null);
			}
		}
		// 左空,右空
		if (parent.getLeft() == null && node.getParent().getRight() == null) {
			if (parent.getParent() != null) {
				leftOrRightNoOnOne(parent.getParent(), node);
				node.setParent(parent.getParent());
				node.setRight(parent.getRight());
				parent.getRight().setParent(node);
				parent.getRight().setLeft(null);
				node.setLeft(parent);
				parent.setParent(node);
				parent.setRight(null);
			} else {
				root = node;
				node.setLeft(parent);
				parent.setParent(node);
				parent.setRight(null);
				node.setRight(node.getParent());
				node.getParent().setParent(node);
				node.getParent().setLeft(null);
			}
		}
		root.setParent(null);
		opRoot = root ;
		leftAndRightBalance(opRoot);
		
	}
	// 这个是用来检查左右方法平衡不平衡,两边的深度差是否小于等于1,如果大于1了,根据方向旋转;
	private void leftAndRightBalance(Node<T> opRoot) {
		int left = treeDepth(opRoot.getLeft()) ;
		int right = treeDepth(opRoot.getRight()) ;
		if(left - right > 1){
			rightxuanzhuan(opRoot);
			return ;
		}
		if(right - left > 1){
			leftxuanzhuan(opRoot);
			return ;
		}
	}
	// 这里是左旋转的
	private void rightxuanzhuan(Node<T> opRoot) {
		Node<T> parent = opRoot.getParent();
		Node<T> left = opRoot.getLeft();
		Node<T> right = opRoot.getRight();
		Node<T> rightLeft = findLeft(right);
		if(rightLeft.getT().compareTo(right.getT()) == 0){
			rightLeft = null ;
		}
		newxuanzhuan(rightLeft);
		left.setParent(parent);
		if(parent != null){
			parent.setLeft(left);
		}else {
			root = left ;
			left.setParent(null);
		}
		if(rightLeft != null){
			rightLeft.setLeft(left.getLeft());
			if(left.getLeft()!=null){
				left.getLeft().setParent(rightLeft);
			}
		}else{
			opRoot.setLeft(left.getRight());
			if(left.getRight() != null){
				left.getRight().setParent(opRoot);
			}
		}
		left.setRight(opRoot);
		zaipanduan(left);
	}
	private void zaipanduan(Node<T> left) {
		if(left != null && left.getLeft() != null){
			zaipanduan(left.getLeft());
		}
		if(left !=null && left.getRight() != null){
			zaipanduan(left.getRight());
		}
		zaipanduandigui(left);
	}
	private void zaipanduandigui(Node<T> left){
		xuanzhuanshu(left);
	}
	private void leftxuanzhuan(Node<T> opRoot) {
		Node<T> parent = opRoot.getParent();
		Node<T> right = opRoot.getRight();
		Node<T> rightleft = findLeft(right);
		newxuanzhuan(rightleft);
		right.setParent(parent);
		if(parent != null){
			parent.setRight(right);
		}else{
			root = right;
		}
		if(rightleft != null){
			rightleft.setLeft(opRoot);
			opRoot.setParent(rightleft);
		}else{
			right.setLeft(opRoot);
			opRoot.setParent(right);
		}
		opRoot.setRight(null);
		zaipanduan(right);
	}
	// 为上面这两个类提供的旋转
	private void newxuanzhuan(Node<T> rightleft) {
		if(rightleft == null){
			return ;
		}
		Node<T> parent = rightleft.getParent();
		if(parent == null || parent.getRight() != null){
			return ;
		}
		rightleft.setParent(parent.getParent());
		
		if(parent.getParent().getLeft() != null && parent.getParent().getLeft().getT().compareTo(parent.getT()) == 0){
			parent.getParent().setLeft(parent.getLeft());
		}else{
			parent.getParent().setRight(parent.getLeft());
		}
		
		rightleft.setRight(parent);
		parent.setParent(rightleft);
		parent.setLeft(null);
		
	}
	// 这个用于处理,不是连续的
	private void leftOrRightNoOnOne(Node<T> parent, Node<T> son) {
		if (parent.getLeft().getT().compareTo(son.getParent().getParent().getT()) == 0) {
			parent.setLeft(son);
		} else {
			parent.setRight(son);
		}

	}
	// 处理连续的
	private void leftOrRight(Node<T> parent, Node<T> son) {
		
		if (parent.getLeft() != null && parent.getLeft().getT()
				.compareTo(son.getParent().getT()) == 0) {
			parent.setLeft(son);
		} else {
			parent.setRight(son);
		}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值