学了二叉排序树https://blog.csdn.net/qq_44025894/article/details/107452151,虽然起到了增加查找效率的效果,但是有些特殊情况下的树还是很影响效率。比如
树的高度太高了查找起来效率依然不高。
而平衡树解决了这个问题。
平衡树的每一个节点的子树高度之差的绝对值不超过 1 .
其他规则和二叉排序树一样。
平衡树比较难的方法是如何判断此时已经不满足平衡树的定义了
节点Node中的方法:
//返回左子树的高度
public int getLeftHeight(){
if (left == null)
return 0;
else
return left.getHeight();
}
//返回右子树的高度
public int getRightHeight(){
if (right == null)
return 0;
else
return right.getHeight();
}
//返回当前节点的高度,以该节点为根节点的高度
public int getHeight(){
return Math.max(left == null? 0:left.getHeight(),right == null? 0:right.getHeight()) + 1;
}
第三个方法getHeight最重要,其目的是返回当前节点的高度,比如上图的8节点,此方法返回的就是3.
方法三的结论是:
此树的深度 等于 左子树的深度 与 右子树的深度 中的 最大值 +1
这个方法中利用了递归和max方法。先判断左子树是否为空,为空则此三元表达式返回0,在以同样的条件判断右子树。如果是叶子节点,则自然返回1.而如果是非叶子节点,三元表达式就会往下递归,而且max函数会保证返回的一定是两个子树中高度较高的。并且每次递归会+1,所以最后得到的就是以当前节点为根节点的高度。
有了这三个方法,我们就可以确定一棵树是不是平衡树了。如果不是平衡树应该怎么处理呢?这里涉及到3个方法,左旋,右旋和双旋。
先看左旋:
//左旋转
public void leftRotate(){
//创建新节点,值为当前根节点的值
Node temp = new Node(val);
//新节点的左子树设置为当前节点的左子树
temp.left = left;
//新节点右子树设置为当前节点右子树的左子树
temp.right = right.left;
//当前节点的值替换成右子节点的值
val = right.val;
//把当前节点的右子树设为当前节点右子树的右子树
right = right.right;
//当前节点的左子树设为新的节点
left = temp;
}
添加节点时在满足getRightHeight() - getLeftHeight() > 1 的条件时经过上面左旋的处理就可以成为一颗平衡树。
同理满足getLeftHeight() - getRightHeight() > 1的条件时应该右旋转处理。
//右旋转
public void rightRotate(){
Node temp = new Node(val);
temp.right = right;
temp.left = left.right;
val = left.val;
left = left.left;
right = temp;
}
现在有一种情况:
此时右旋后的树依然不是平衡树,因为如果右旋时其左子节点的右子树的高度大于其左子节点的左子树(7节点的右子树高度大于7节点的左子树高度),则会失败。左旋时同理。
解决办法是在进行右旋时,先对其左子节点进行左旋。所以添加节点的完整方法是
public void addNode(Node node){
if (node == null)
return;
if (node.val < this.val){
if (this.left == null){
this.left = node;
}else {
this.left.addNode(node);
}
}else {
if (this.right == null){
this.right = node;
}else {
this.right.addNode(node);
}
}
//左旋转
if (getRightHeight() - getLeftHeight() > 1){
if (right != null && right.getLeftHeight() > right.getRightHeight()){
right.rightRotate();
}
leftRotate();
return;
}else if (getLeftHeight() - getRightHeight() > 1){//右旋转
if (left != null && left.getRightHeight() > left.getLeftHeight()){
left.leftRotate();
}
rightRotate();
}
}