代码较长,放在最后了
既然是平衡二叉树就离不开平衡因子的概念
每个节点都有一个平衡因子, 定义为int型 值是该节点的左子树高度减去右子树高度(有的地方是右-左,无所谓,自己保持一致就好)
如果是负的说明右子树高度高于左子树
平衡二叉树要求树中每个节点的平衡因子绝对值不大于1(即可以是 -1 0 1)
这里不介绍不平衡时具体的旋转方法, 只是列举我写的时候遇到的坑和要点,予以帮助掉到相同坑里的人
- 代码中大量使用了递归, 递归第一步就要写跳出条件, 照顾好递归的开头和结尾, 注意对根元素的判断, 根元素无父亲节点
- void 无返回值方法也可以使用return;提前跳出方法
- 平衡因子的更新是最难的点, 当插入节点后要判断父节点是否高度增加(也就是原来的平衡因子是否是0) ,当父元素的平衡因子改变父元素的父元素平衡因子不一定改变,也就是说判断是否向树根递归修改平衡因子的判断条件不是平衡因子是否改变, 而是高度是否增加, 如果插入后节点平衡因子更新后不等于0则递归向上修改(改后!=0说明高度增加了,影响其父节点的平衡因子)
- 判断旋转后修改区域内平衡因子的调整分几种情况, 可以参考这个大佬的分析, 有图示:https://blog.csdn.net/skyroben/article/details/72824146
- 旋转后和删除节点后对该区域上的父级元素平衡因子是否有影响的判定条件也是判断该子树高度是否改变, 但又和插入不同,需要判断该子树的平衡因子修改前和修改后的相对大小, 修改后比修改前更趋于0则向上递归(改前>0&&改后<改前)||(改前<0&&改后>改前)为真则修改其父元素的平衡因子
- 删除时也分为几类,网上的分析也很多, 写好判断调用插入时写好的旋转方法和平衡调节方法也不难, 注意删除一个叶子节点时不能直接在方法中把节点的引用直接赋值null, 因为这样会断开引用与对象的联系但节点对象还在二叉树上(父节点的指针还指向他), 具体原因是JAVA是值传递并非引用传递,方法操作的是引用的拷贝,删除叶子节点需要找到父节点, 把父节点指向它的引用设为null,这样就从树上删除了这个节点, 新手可能有疑问,怎么这就能直接赋null? 因为指向孩子的引用是对象的一个属性, 不是方法中传进来的, 传进来的是指向父节点的指针. 如果这样说还不理解 , 可以看下我的另一篇博客介绍JAVA参数的传递方式:https://blog.csdn.net/q5706503/article/details/82910428
代码是一个main类 一个节点Node类 一个平衡二叉树Tree类:
package treeAVL;
public class Node
{
private int number;
private int balance; //节点的平衡因子,设定为 左-右
private Node left,right,father;
Node(int num){this.number=num;}
public void setNumber(int num) {this.number=num;}
public int getNumber() {return this.number;}
public int getBalance() {return this.balance;}
public void riseBalance() {this.balance++;}
public void downBalance() {this.balance--;}
public Node getLeft() {return this.left;}
public void setLeft(Node node) {this.left=node;}
public Node getRight() {return this.right;}
public void setRight(Node node) {this.right=node;}
public Node getFather() {return this.father;}
public void setFather(Node node) {this.father=node;}
}
package treeAVL;
import javax.print.attribute.standard.RequestingUserName;
public class Tree {
private Node root;
//内部插入函数,递归用
private void innerInsert(Node newNode,Node rootNode)
{
if(newNode.getNumber()==rootNode.getNumber())
{
System.out.println("存在该数,插入失败!");
return;
}
if(newNode.getNumber()<rootNode.