JAVA数据结构与算法之————平衡二叉树
平衡二叉树 又称AVL树,平衡二叉树具有的特性是:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
本文将从以下几个方面进行介绍:
- TreeNode结构介绍。
- 向平衡二叉树中插入元素,然后调整二叉树使其仍然为平衡二叉树。
- 创建平衡二叉树。
- 删除平衡二叉树中的节点。
介绍TreeNode结构:
由于我在博客JAVA数据结构与算法之————二叉树中给出了TreeNode的结构,这里就不多重复了。
向平衡二叉树中插入元素,然后调整二叉树使其仍然为平衡二叉树:
向平衡二叉树中插入可能造成以下4种不平衡的情况:
1:如图1
节点5的平衡因子为2,所以应该进行右旋调整,调整后如图2:
具体实现过程看右旋代码(结合上图进行解释):
// 右旋操作
public TreeNode<E> rightRotate(TreeNode<E> T) {
// T为上图1中的节点5,p为节点3
TreeNode<E> p = T.getlChild();
// 结点4作为结点5的左子树接入
T.setlChild(p.getrChild());
// 结点5作为结点3的的右子树接入
p.setrChild(T);
// 如果结点4存在,则设置4的父节点为结点5
if (T.getlChild() != null) {
T.getlChild().setParent(T);
}
// 让3变成5的父节点
p.setParent(T.getParent());
if (p.getParent() != null) {
if (T == T.getParent().getlChild()) {
p.getParent().setlChild(p);
} else {
p.getParent().setrChild(p);
}
}
T.setParent(p);
/*这里有一个需要注意的点是,要先跟新结点5的高度和平衡因子,在跟新结点3的*/
T.setDepth(calDepth(T));
T.setBalance(calBalance(T));
p.setDepth(calDepth(p));
p.setBalance(calBalance(p));
return p;
}
图1不平衡的二叉树经过右旋调整变成图2的平衡二叉树。
2,如图3
图3中2的平衡因子为-2,需要进行左旋操作,调整后如图4:
具体看代码(左旋和右旋类似):
// 左旋 ,基本和右旋类似
public TreeNode<E> leftRotate(TreeNode<E> T) {
TreeNode<E> p = T.getrChild();
T.setrChild(p.getlChild());
p.setlChild((T));
if (T.getrChild() != null) {
T.getrChild().setParent(T);
}
p.setParent(T.getParent());
if (p.getParent() != null) {
if (T == T.getParent().getlChild()) {
p.getParent().setlChild(p);
} else {
p.getParent().setrChild(p);
}
}
T.setParent(p);
T.setDepth(calDepth(T));
T.setBalance(calBalance(T));
p.setDepth(calDepth(p));
p.setBalance(calBalance(p));
return p;
}
3,如图5:
如图5,结点5的平衡因子为2,结点2的平衡因子为-1,它们的平衡因子符号相反,这种情况应该对根结点为2的子树进行左旋炒作,然后对根节点为5的子树进行右旋操作,调整后如图6:
4,如图7:
如图7,结点5的平衡因子为-2,结点2的平衡因子为1,它们的平衡因子符号相反,这种情况应该对根结点为5的子树进行右旋操作,然后对根节点为2的子树进行左旋操作,调整后如图8:
上代码:
public void adjust(TreeNode<E> T){
// 如果T的平衡因子大于等于2,或者小于等于-2,,都需要对以T为跟节点的子树进行旋转调整
if (T.getBalance() >= 2) {
// 当T的平衡因和T左子树的平衡因子符号相反,需要先对T的左子树进行左旋操作,再对T进行右旋操作
if (T.getlChild().getBalance() == -1) {
leftRotate(T.getlChild());
}
rightRotate(T);
}
// 与T的平衡因子为2的情况相似,先对T的右子树进行右旋操作,再对T进行左旋操作
if (T.getBalance() <= -2) {
if (T.getrChild().getBalance() == 1) {
rightRotate(T.getrChild());
}
leftRotate(T);
}
}
下面就正式进入插入代码:
/*
*向平衡二叉树中插入元素
* */
public void insert(TreeNode<E> T, E data) {
//如果data小于T的值,进入T的左子树
if (data.compareTo(T.getData()) < 0) {
if (T.getlChild() != null) {
//如果左子树不为空,这递归左子树
insert(T.getlChild()