Java数据结构——平衡二叉树

本文详细介绍了平衡二叉树的概念,包括它的性质和平衡因子,以及解决失衡问题的四种情况和对应的旋转操作。通过左旋和右旋策略,确保了树的平衡,从而提高查询效率。此外,还展示了如何在添加和删除节点时保持平衡,以及相应的代码实现。
摘要由CSDN通过智能技术生成

平衡二叉树:

在二叉排序树的创建中,若创建序列不恰当,可能会导致二叉排序树高度过大,甚至变成单链表

如序列1 2 3 4 5 6,显然每次插入新节点,都在右子树上插入,形成一个单链表

此时对该树的查询效率降低,没有发挥出二叉排序树的优势,为了解决这一问题,引入平衡二叉树

平衡二叉树满足以下两个条件

(1)是二叉排序树

(2)左右子树均为平衡二叉树,且高度差不大于1

空树也为平衡二叉树,且一般将某个节点的左右子树高度差称为该节点的平衡因子,记作BF


实现思路:

对于二叉树的失衡情况,可以简化为以下四种

LL型:

RR型:

LR型:

RL型:

这四种情况均需利用到二叉树的左旋和右旋进行处理,下面先介绍左旋和右旋

左旋:

如图可以看出,左旋是将整棵树向左边(逆时针)进行旋转,其中,根节点右子树的左子树,在旋转后变成根节点左子树的右子树,具体算法如下:

(1)以当前节点的值创建新节点

(2)把新的节点的左子树设置为当前节点的左子树

(3)把新的节点的右子树设置为当前节点右子树的左子树

(4)把当前节点的值修改为右孩子的值

(5)把当前节点的右子树设置为右孩子的右子树

(6)把当前节点的左孩子设置为新节点

经过这样的操作后,原先二叉树中会有一个节点(在本例中为3)会由于没有任何指针指向它,被Java的GC自动回收

注意的是,左旋和右旋是针对某个节点进行的,也就是说,算法中的当前节点即为进行左旋和右旋的节点,如本例中当前节点为根节点,此时根节点的平衡因子的绝对值大于1

右旋:

与左旋正好相反,具体算法如下:

(1)以当前节点的值创建新节点

(2)把新的节点的右子树设置为当前节点的右子树

(3)把新的节点的左子树设置为当前节点左子树的右子树

(4)把当前节点的值修改为左孩子的值

(5)把当前节点的左子树设置为左孩子的左子树

(6)把当前节点的右孩子设置为新节点

对于LL型和RR型,只需要从下往上找到第一个不平衡(平衡因子的绝对值大于1)的节点,进行左旋或右旋即可

对于LR型和RL型,需要进行两次旋转,具体如下:

LR型:先对左孩子进行左旋,再对根节点进行右旋

RL型:先对右孩子进行右旋,再对根节点进行左旋

为了判断节点是否平衡,还需设计获取子树高度的方法,按照树高等于左右子树的最大高度 + 1的思想,设计递归方法进行计算即可,较为简单

对于四种类型的判断,首先比较左右子树高度的关系,确定左旋还是右旋,然后进一步判断其左孩子(右孩子)的左右子树高度的关系,来确定是否需要两次旋转,四种情况如下:

LL型:左子树与右子树高度之差大于1,且左子树的左子树高度不小于左子树的右子树高度

LR型:左子树与右子树高度之差大于1,且左子树的左子树高度小于左子树的右子树高度

RR型:右子树与左子树高度之差大于1,且右子树的右子树高度不小于右子树的左子树高度

RL型:右子树与左子树高度之差大于1,且右子树的右子树高度小于右子树的左子树高度

在添加节点和删除节点中,都通过递归,实现了从下往上的平衡处理


代码实现:

节点类AVLTreeNode:

public class AVLTreeNode {
	public int data;
	public AVLTreeNode left;
	public AVLTreeNode right;

	public AVLTreeNode(int data) {
		this.data = data;
	}

	//返回左子树高度
	public int getLeftHeight() {
		if (left == null) {
			return 0;
		}
		return left.getHeight();
	}

	//返回右子树高度
	public int getRightHeight() {
		if (right == null) {
			return 0;
		}
		return right.getHeight();
	}

	//返回当前节点为根节点的树的高度
	public int getHeight() {
		return Math.max(left == null ? 0 : left.getHeight(), right == null ? 0 : right.getHeight()) + 1;
	}

	//左旋转
	public void leftRotate() {
		AVLTreeNode newNode = new AVLTreeNode(data);
		newNode.left = left;
		newNode.right = right.left;
		data = right.data;
		right = right.right;
		left = newNode;
	}

	//右旋转
	public void rightRotate() {
		AVLTreeNode newNode = new AVLTreeNode(data);
		newNode.right = right;
		newNode.left = left.right;
		data = left.data;
		left = left.left;
		right = newNode;
	}

	//添加节点
	public void add(AVLTreeNode node) {
		if (node == null) {
			return;
		}
		if (node.data < this.data) {
			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);
			}
		}
		if (getRightHeight() - getLeftHeight() > 1) {
			if (right.getLeftHeight() > right.getRightHeight()) {
				right.rightRotate();
			}
			leftRotate();

		} else if (getLeftHeight() - getRightHeight() > 1) {
			if (left.getRightHeight() > left.getLeftHeight()) {
				left.leftRotate();
			}
			rightRotate();
		}
	}

	//查找待删除的节点
	public AVLTreeNode search(int data) {
		if (data == this.data) {
			return this;
		} else if (data < this.data) {
			if (this.left == null) {
				return null;
			}
			return this.left.search(data);
		} else {
			if (this.right == null) {
				return null;
			}
			return this.right.search(data);
		}
	}

	//查找待删除节点的父节点
	public AVLTreeNode searchParent(int data) {
		if (this.left != null && this.left.data == data || this.right != null && this.right.data == data) {
			return this;
		} else {
			if (this.left != null && data < this.data) {
				return this.left.searchParent(data);
			} else if (this.right != null && data >= this.data) {
				return this.right.searchParent(data);
			} else {
				return null;
			}
		}
	}

	//删除节点后平衡二叉树递归方法
	public void balanceAfterDelete(AVLTreeNode parentNode) {
		if (parentNode.data < this.data) {
			this.left.balanceAfterDelete(parentNode);
		} else if (parentNode.data > this.data) {
			this.right.balanceAfterDelete(parentNode);
		}
		if (getRightHeight() - getLeftHeight() > 1) {
			if (right.getLeftHeight() > right.getRightHeight()) {
				right.rightRotate();
			}
			leftRotate();

		} else if (getLeftHeight() - getRightHeight() > 1) {
			if (left.getRightHeight() > left.getLeftHeight()) {
				left.leftRotate();
			}
			rightRotate();
		}
	}

	//中序遍历
	public void inOrder() {
		if (this.left != null) {
			this.left.inOrder();
		}
		System.out.println(this);
		if (this.right != null) {
			this.right.inOrder();
		}
	}

	@Override
	public String toString() {
		return "AVLTreeNode{" + "data=" + data + '}';
	}
}

平衡二叉树类AVLTree:

public class AVLTree {
	public AVLTreeNode root;

	//返回高度
	public int getHeight() {
		return root.getHeight();
	}

	//添加节点
	public void add(AVLTreeNode node) {
		if (root == null) {
			root = node;
		} else {
			root.add(node);
		}
	}

	//查找待删除的节点
	public AVLTreeNode search(int data) {
		if (root == null) {
			return null;
		} else {
			return root.search(data);
		}
	}

	//查找待删除节点的父节点
	public AVLTreeNode searchParent(int data) {
		if (root == null) {
			return null;
		} else {
			return root.searchParent(data);
		}
	}

	//查找以node为根节点的二叉排序树的最小节点的值
	public int deleteRightTreeMin(AVLTreeNode node) {
		AVLTreeNode targetNode = node;
		while (targetNode.left != null) {
			targetNode = targetNode.left;
		}
		delete(targetNode.data);
		return targetNode.data;
	}

	//删除节点
	public void delete(int data) {
		if (root == null) {
			return;
		} else {
			AVLTreeNode targetNode = search(data);
			if (targetNode == null) {
				return;
			}
			if (root.left == null && root.right == null) {
				root = null;
				return;
			}
			AVLTreeNode parentNode = searchParent(data);
			if (targetNode.left == null && targetNode.right == null) {
				if (parentNode.left != null && parentNode.left.data == data) {
					parentNode.left = null;
				} else if (parentNode.right != null && parentNode.right.data == data) {
					parentNode.right = null;
				}
			} else if (targetNode.left != null && targetNode.right != null) {
				targetNode.data = deleteRightTreeMin(targetNode.right);
			} else {
				if (targetNode.left != null) {
					if (parentNode != null) {
						if (parentNode.left.data == data) {
							parentNode.left = targetNode.left;
						} else {
							parentNode.right = targetNode.left;
						}
					} else {
						root = targetNode.left;
					}
				} else {
					if (parentNode != null) {
						if (parentNode.left.data == data) {
							parentNode.left = targetNode.right;
						} else {
							parentNode.right = targetNode.right;
						}
					} else {
						root = targetNode.right;
					}
				}
			}
			balanceAfterDelete(parentNode);
		}
	}

	//删除节点后平衡二叉树递归方法
	public void balanceAfterDelete(AVLTreeNode parentNode) {
		root.balanceAfterDelete(parentNode);
	}

	//中序遍历
	public void inOrder() {
		if (this.root != null) {
			this.root.inOrder();
		} else {
			System.out.println("二叉树为空");
		}
	}
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值