二叉排序树的添加与删除

二叉排序树的概述

二叉排序树:BST(Binary Sort(Search) Tree), 对于二叉排序树的任何一个非叶子节点,
要求当前节点值大于其左子节点值,当前节点值小于其右子节点值
特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点

代码所对应的 数组 与 二叉排序树 如下

数组{7, 3, 10, 12, 5, 1, 9, 2} 

数组对应的二叉排序树

package com.zzb.tree;

import java.io.Serializable;

/**
 * @Auther: Administrator
 * @Date: 2019/10/14 00:07
 * @Description:
 * 二叉排序树:BST(Binary Sort(Search) Tree), 对于二叉排序树的任何一个非叶子节点,
 * 要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大
 * 特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点
 */
public class BinaryTreeDemo03 {
    public static void main(String[] args) {
        // 添加元素
        testAdd();
        // 删除节点
        testDelOne();
    }

    /**
     * 测试添加元素节点
     * 根据数组创建成对应的二叉排序树,并使用中序遍历二叉排序树,比如:数组为{7, 3, 10, 12, 5, 1, 9, 2}
     */
    private static void testAdd() {
        // 创建二叉排序树
        BinarySortTree binarySortTree = new BinarySortTree();
        // 数组
        int[] arr = {7, 3, 10, 12, 5, 1, 9, 2};
        for (int i = 0; i < arr.length; i++) {
            // 添加元素节点
            binarySortTree.add(new Node(arr[i]));
        }
        // 中序遍历
        System.out.println("----------------中序遍历----------------");
        binarySortTree.infixOrder();
        /*----------------中序遍历----------------
        Node{value=1}
        Node{value=2}
        Node{value=3}
        Node{value=5}
        Node{value=7}
        Node{value=9}
        Node{value=10}
        Node{value=12}*/
    }

    // 测试删除节点
    private static void testDelOne() {
        // 创建二叉排序树
        BinarySortTree binarySortTree = new BinarySortTree();
        // 数组
        int[] arr = {7, 3, 10, 12, 5, 1, 9, 2};
        for (int i = 0; i < arr.length; i++) {
            // 添加元素节点
            binarySortTree.add(new Node(arr[i]));
        }
        System.out.println("----------------删除节点前的中序遍历----------------");
        binarySortTree.infixOrder();
        // 删除节点
        binarySortTree.delOne(9);
        System.out.println("----------------删除节点后的中序遍历----------------");
        binarySortTree.infixOrder();
    }
}

// 二叉排序树
class BinarySortTree {

    private Node root;

    // 二叉排序树添加元素节点
    public void add(Node node) {
        // 根节点非空判断
        if(this.getRoot() == null) { // null
            this.setRoot(node);
        } else { // not null
            this.getRoot().add(node);
        }
    }

    // 二叉排序树中序遍历
    public void infixOrder() {
        if(this.getRoot() == null) {
            System.out.println("二叉树为空,无法遍历!");
        } else {
            this.getRoot().infixOrder();
        }
    }

    // 二叉排序树删除节点
    /*有三种情况需要考虑
    (1)删除叶子节点 (比如:2, 5, 9, 12)
    (2)删除只有一颗子树的节点 (比如:1)
    (3)删除有两颗子树的节点(比如:7, 3, 10 )*/
    /*
    第一种情况:
    删除叶子节点 (比如:2, 5, 9, 12)
    思路
    (1) 需求先去找到要删除的结点 targetNode
    (2) 找到 targetNode 的 父结点 parent
    (3) 确定 targetNode 是 parent 的左子结点 还是右子结点
    (4) 根据前面的情况来对应删除
    左子结点 parent.left = null
    右子结点 parent.right = null

    第二种情况: 删除只有一颗子树的节点 (比如:1)
    思路
    (1) 需求先去找到要删除的结点 targetNode
    (2) 找到 targetNode 的 父结点 parent
    (3) 确定 targetNode 的子结点是左子结点还是右子结点
    (4) targetNode 是 parent 的左子结点还是右子结点
    (5) 如果 targetNode 有左子结点
        5.1) 如果 targetNode 是 parent 的左子结点
        parent.left = targetNode.left
        5.2) 如果 targetNode 是 parent 的右子结点
        parent.right = targetNode.left
    (6) 如果 targetNode 有右子结点
        6.1) 如果 targetNode 是 parent 的左子结点
        parent.left = targetNode.right
        6.2) 如果 targetNode 是 parent 的右子结点
        parent.right = targetNode.right

    情况三 : 删除有两颗子树的节点. (比如:7, 3, 10 )
    思路
    (1) 需求先去找到要删除的结点 targetNode
    (2) 找到 targetNode 的 父结点 parent
    (3) 从 targetNode 的右子树找到最小的结点
    (4) 用一个临时变量,将 最小结点的值保存 temp
    (5) 删除该最小结点
    (6) targetNode.value = temp*/
    public void delOne(int value) {
        // 根节点非空判断
        if(this.getRoot() == null) {
            return;
        } else {
            // (1) 需求先去找到要删除的结点 targetNode
            Node targetNode = search(value);
            // 没有找到要删除的节点
            if(targetNode == null) {
                return;
            }
            // 走到该位置,并且二叉排序树只有一个跟节点
            if(this.getRoot() != null
                    && this.getRoot().getLeft() == null
                    && this.getRoot().getRight() == null) {
                this.setRoot(null);
                return;
            }
            // (2) 找到 targetNode 的 父结点 parent
            Node parentNode = searchParent(value);
            // 情况一:要删除的节点时叶子节点
            if(targetNode.getLeft() == null && targetNode.getRight() == null) {
                // 判断是左叶子节点、还是有叶子节点
                if(parentNode.getLeft() != null && parentNode.getLeft().getValue() == value) { // 左子节点
                    parentNode.setLeft(null);
                } else if(parentNode.getRight() != null && parentNode.getRight().getValue() == value) { // 右子节点
                    parentNode.setRight(null);
                }
            // 情况三:要删除的节点存在左、右子树
            } else if(targetNode.getLeft() != null && targetNode.getRight() != null) {
                // 从 targetNode 的右子树找到最小的结点
                Integer minVal = delRightTreeMin(targetNode.getRight());
                targetNode.setValue(minVal);
            } else { // 情况二:要删除的节点存在一棵子树
                if(targetNode.getLeft() != null) { // targetNode有左子节点
                    if(parentNode != null) {
                        if(parentNode.getLeft().getValue() == value) { // targetNode是parentNode的左子节点
                            parentNode.setLeft(targetNode.getLeft());
                        } else { // targetNode是parentNode的右子节点
                            parentNode.setRight(targetNode.getLeft());
                        }
                    } else {
                        this.setRoot(targetNode.getLeft()); // 删除的是根节点,则根节点就不会存在父节点这种情况
                    }
                } else { // targetNode有右子节点
                    if(parentNode != null) {
                        if(parentNode.getLeft().getValue() == value) { // targetNode是parentNode的左子节点
                            parentNode.setLeft(targetNode.getRight());
                        } else { // targetNode是parentNode的右子节点
                            parentNode.setRight(targetNode.getRight());
                        }
                    } else {
                        this.setRoot(targetNode.getRight()); // 删除的是根节点,则根节点就不会存在父节点这种情况
                    }
                }
            }
        }
    }

    // 找到要删除的结点 targetNode
    private Node search(Integer value) {
        if(this.getRoot() == null) {
            return null;
        } else {
            return this.getRoot().search(value);
        }
    }

    // 找到 targetNode 的 父结点 parentNode
    private Node searchParent(Integer value) {
        if(this.getRoot() == null) {
            return null;
        } else {
            return this.getRoot().searchParent(value);
        }
    }

    /**
     * 从 targetNode 的右子树找到最小的结点
     * @param node 传入的结点(当做二叉排序树的根结点)
     * @return 返回的 以node为根结点的二叉排序树的最小结点的值
     */
    private Integer delRightTreeMin(Node node) {
        Node target = node;
        // 循环遍历左子节点,就会找到最小值的节点
        while (target.getLeft() != null) {
            target = target.getLeft();
        }
        // 删除最小节点,就是删除叶子节点的情况
        delOne(target.getValue());
        return target.getValue();
    }

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }
}

// 元素节点类
class Node implements Serializable {

    private static final long serialVersionUID = 5554155106585225764L;

    private Integer value;
    private Node left;
    private Node right;

    // 添加元素节点
    public void add(Node node) {
        // 待添加节点的非空判断
        if(node == null) {
            return;
        }
        if(this.getValue() > node.getValue()) { // 当前节点大于添加节点
            if(this.getLeft() == null) { // 添加到当前节点的左边
                this.setLeft(node);
            } else { // 递归判断
                this.getLeft().add(node);
            }
        } else { // 当前节点小于添加节点
            if(this.getRight() == null) { // 添加到当前节点的右边
                this.setRight(node);
            } else { // 递归调用
                this.getRight().add(node);
            }
        }
    }

    // 查找要删除的节点
    public Node search(Integer value) {
        if(this.getValue() == value) { // 当前节点等于查找节点
            return this;
        } else if(this.getValue() > value) { // 当前节点大于查找节点
            if(this.getLeft() == null) {
                return null;
            } else { // 左子树找
                return this.getLeft().search(value);
            }
        } else { // 当前节点小于查找节点
            if(this.getRight() == null) {
                return null;
            } else { // 右子树找
               return this.getRight().search(value);
            }
        }
    }

    // 查找要删除节点的父节点
    public Node searchParent(Integer value) {
        if((this.getLeft() != null && this.getLeft().getValue() == value)
                || (this.getRight() != null && this.getRight().getValue() == value)) {
            return this;
        } else {
            if(this.getValue() > value && this.getLeft() != null) { // 左子树找
                return this.getLeft().searchParent(value);
            } else if(this.getValue() < value && this.getRight() != null) { // 右子树找
                return this.getRight().searchParent(value);
            } else { // 没找到父节点
                return null;
            }
        }
    }

    /**
     * 中序遍历
     * 每个节点都会执行中序遍历方法中的三个动作,涉及到递归方法的压栈与弹栈
     */
    public void infixOrder() {
        // (1)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行中序遍历方法进行中序遍历
        if(this.getLeft() != null) {
            this.getLeft().infixOrder();
        }
        // (2)输出当前节点(初始节点是根节点root节点)
        System.out.println(this);
        // (3)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行中序遍历方法进行中序遍历
        if(this.getRight() != null) {
            this.getRight().infixOrder();
        }
    }

    public Node(Integer value) {
        this.value = value;
    }

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "Node{" +
                "value=" + value +
                '}';
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值