JAVA-数据结构与算法-二叉排序树

210 阅读2分钟

写在前面

二叉排序树

  • 任何一个非叶子节点,左子节点比当前节点小,右子节点的值比当前节点大
  • 右边的数都比左边大
  • 对二叉排序树,进行中序遍历就是升序输出的

创建和添加

  • 二叉排序树
class BinarySortTree {
    private Node root;
    //添加
    public void add(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.add(node);
        }
    }
    //中序遍历
    public void infixOrder() {
        if (root != null) {
            root.infixOrder();
        } else {
            System.out.println("empty");
        }
    }
}
  • 节点
class Node {
    int value;
    Node left;
    Node right;

    //递归的形式添加,满足二叉排序树
    public void add(Node node) {
        if (node == null) {
            return;
        }
        //判断传入的值
        if (node.value < this.value) {
            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);
            }
        }
    }
    //中序遍历
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixOrder();
        }
    }
    //toString constructor...
}

删除

  • 删除叶子节点
  • 删除只有一颗子树的节点
  • 删除有两棵子树的节点

节点方法

  • 查找要删除的节点
public Node search(int value) {
    if (value == this.value) {
        return this;
    } else if (value < this.value) {
        //查找的值小于当前节点,左子树找
        if (this.left == null) {
            return null;
        }
        return this.left.search(value);
    } else {
        if (this.right == null) {
            return null;
        }
        return this.right.search(value);
    }
 }
  • 查找要删除节点的父节点,默认要删除的节点不是root,root在树中处理
public Node searchParent(int value) {
    if ((this.left != null && this.left.value == value) ||
            (this.right != null && this.right.value == value)) {
        return this;
    } else {
        //如果查找的值小于当前节点的值,并且当前节点的左子节点不为空
        //当进入这个查找父节点方法时,表明这个节点一定不是根节点
        //如果这个节点的值==value,已经被上面的判断语句判断过了,那么父节点在上一层就已经找到
        //所以,到这个判断时,就不可能出现等于的情况
        if (value < this.value && this.left != null) {
            return this.left.searchParent(value);
        } else if (value > this.value && this.right != null) {
            return this.right.searchParent(value);
        } else {
            return null;
        }
    }
}

树方法

  • 查找要删除的节点
public Node search(int value) {
    if (root == null) {
        return null;
    } else  {
        if (root.value == value) {
            return root;
        }
        return root.search(value);
    }
}
  • 查找父节点
public Node searchParent(int value) {
    if (root == null) {
        return null;
    } else {
        if (root.value == value) {
            return null;
        }
        return root.searchParent(value);
    }
}
  • 删除节点
public void delNode(int value) {
    if (root == null) {
        return;
    } else {
        Node targetNode = search(value);
        if (targetNode == null) {
            return;
        }
        //找到targetNode的父节点
        Node parent = searchParent(value);
        //说明找到了root
        if (parent == null) {
            //如果当前只有一个节点,找到了要删除的节点,而且当前节点还只有一个节点,那么就是根节点
            if (root.left == null && root.right == null) {
                root = null;
                return;
            } else if (root.left != null && root.right == null) {
                //如果只有左边有
                root = root.left;
                return;
            }
            else if (root.left == null && root.right != null) {
                root = root.right;
                return;
            }
            //两边都有,跟第二种情况一致处理
        }
        //第一种情况,如果删除的节点是叶子节点
        if (targetNode.left == null && targetNode.right == null) {
            //判断targetNode是父节点的左子节点或者右子节点
            if (parent.left != null && parent.left.value == value) {
                parent.left = null;
            } else if (parent.right != null && parent.right.value == value) {
                parent.right = null;
            }
        } else if (targetNode.left != null && targetNode.right != null) {
            //第三种情况,删除有两棵子树的节点
            //在右子树中找最小的,一定是大于左子树的,可以作为新的父节点
            int minValue = delRightTreeMin(targetNode.right);
            targetNode.value = minValue;
        } else {
            //第二种情况,删除一棵子树的节点
            //而targetNode一定是parent的子节点,通过`parent.left != null`保护第一个判断
            //如果不是左子节点,那么就一定是右子节点
            if (targetNode.left != null) {
                if (parent.left != null && parent.left.value == value) {
                    //要删除的节点是父节点的左子节点
                    parent.left = targetNode.left;
                } else {
                    //targetNode是parent的右子节点
                    parent.right = targetNode.left;
                }
            } else {
                //删除的节点有右子节点
                if (parent.left != null && parent.left.value == value) {
                    parent.left = targetNode.right;
                } else {
                    //targetNode是parent的右子节点
                    parent.right = targetNode.right;
                }
            }
        }

    }
}
  • 针对第三种情况,找到右子树中最小的节点(往右子树的左子树一直找),并替代删除的节点的值
/**
 * 返回最小值,并删除
 * @param node 传入的节点,当作二叉排序树的根节点
 * @return 返回以node为根节点的二叉排序树的根节点的最小值
 */
public int delRightTreeMin(Node node) {
    Node target = node;
    //循环查找最小节点
    while (target.left != null) {
        target = target.left;
    }
    delNode(target.value);
    return target.value;
}
  • 针对第三种情况,从左子树的右子树找最大的
public int delLeftTreeMax(Node node) {
    Node target = node;
    //循环查找最小节点
    while (target.right != null) {
        target = target.right;
    }
    delNode(target.value);
    return target.value;
}