二叉排序树【Java实现】

本文介绍了二叉排序树的概念,特点以及如何使用 Java 创建、遍历和删除二叉排序树。在删除操作中详细讨论了删除叶子节点、仅有一棵子树的节点和拥有两棵子树的节点的情况,并提供了相应的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 概念

二叉排序(查找)树( BST:Binary Sort(Search) Tree ):
对于二叉排序树,要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大,如果有相同的值,可以将该值放在左子节点或右子节点。

图示:

2. 二叉排序树的创建与遍历

由二叉排序树的性质可知其中序遍历结果是有序的

代码如下:

public class BinarySortTreeDemo {
    public static void main(String[] args) {
        //初始化数组
        int[] arr = new int[]{9, 3, 45, -2, 7, -23};
        BinarySortTree tree = new BinarySortTree();
        //循环遍历二叉树,将其作为节点加入二叉树
        for (int value : arr) {
            tree.add(new BinarySortTree.Node(value));
        }
        //中序遍历二叉树
        tree.midOrder();
    }
}

class BinarySortTree {
    /**
     * 节点内部类
     */
    static class Node {
        private int value;
        private Node left;
        private Node right;

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

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

        /**
         * 添加节点
         * @param node 待添加的节点
         */
        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 midOrder() {
            if (this.left != null) {
                this.left.midOrder();
            }
            System.out.println(this);
            if (this.right != null) {
                this.right.midOrder();
            }
        }
    }

    private Node root;

    /**
     * @param node 添加节点
     */
    public void add(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.add(node);
        }
    }

    /**
     * 中序遍历
     */
    public void midOrder() {
        if (root == null) {
            System.out.println("当前二叉树为空!无法进行中序遍历!");
        } else {
            root.midOrder();
        }
    }
}

测试结果:

Node{value=-23}
Node{value=-2}
Node{value=3}
Node{value=7}
Node{value=9}
Node{value=45}

3. 二叉排序树的删除

二叉排序树的删除需要考虑下列三种情况(二叉排序树如下图):

  1. 删除叶子节点(如:-23,7,45)
  2. 删除只有一棵子树的节点(如:-2)
  3. 删除只有两棵子树的节点(如:3,9)

二叉排序树:

3.1 删除叶子节点

思路:

1.找到待删除的叶子节点
2.找到待删除节点的父节点
3.判断待删除的节点是左子节点还是右子节点
4.通过父节点直接删除该节点	

3.2 删除只有一棵子树的节点

思路:

1.找到待删除的节点
2.找到待删除节点的父节点 
3.判断待删除节点的子节点是左子节点还是右子节点
4.判断待删除的节点是左子节点还是右子节点
	1.如果待删除节点的子节点是左子节点
		1.如果待删除节点是其父节点的左子节点
			则将其子节点作为其父节点的左子节点
		2.如果待删除节点是其父节点的右子节点
			则将其子节点作为其父节点的右子节点
	2.如果待删除节点的子节点是右子节点
		1.如果待删除节点是其父节点的左子节点
			则将其子节点作为其父节点的左子节点
		2.如果待删除节点是其父节点的右子节点
			则将其子节点作为其父节点的右子节点

3.3 删除有两棵子树的节点

思路:

1.找到待删除的叶子节点
2.找到待删除节点的父节点
3.从待删除节点的右子树找到值最小的节点(也可以找左子树的最大值)
4.用一个临时变量将最小值保存
5.删除最小值节点
6.将最小值赋给待删除节点

3.4 代码实现

代码如下:

public class BinarySortTreeDemo {
    public static void main(String[] args) {
        //初始化数组
        int[] arr = new int[]{9, 3, 45, -2, 7, -23};
        BinarySortTree tree = new BinarySortTree();
        //循环遍历二叉树,将其作为节点加入二叉树
        for (int value : arr) {
            tree.add(new BinarySortTree.Node(value));
        }
        System.out.println("中序遍历二叉树:");
        tree.midOrder();
        System.out.println("删除叶子节点:");
        tree.delNode(7);
        tree.midOrder();
        System.out.println("删除只有一棵子树的节点:");
        tree.delNode(-2);
        tree.midOrder();
        System.out.println("删除有两棵子树的节点:");
        tree.delNode(9);
        tree.midOrder();
    }
}

class BinarySortTree {
    /**
     * 节点内部类
     */
    static class Node {
        private int value;
        private Node left;
        private Node right;

        public Node() {
        }

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

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

        /**
         * 查找当前二叉树中是否存在要删除的节点
         *
         * @param value 要删除的值
         * @return 如果在当前二叉树中存在当前元素,则返回节点;否则,返回 null
         */
        public Node search(int value) {
            if (this.value == value) {
                return this;
            } else if (value < this.value && this.left != null) {
                return this.left.search(value);
            } else if (value > this.value && this.right != null) {
                return this.right.search(value);
            }
            return null;
        }

        /**
         * 查找要删除节点的父节点
         *
         * @param value 要删除的值
         * @return 如果在当前二叉树中存在当前元素节点的父节点,则返回父节点;否则,返回 null
         */
        public Node searchParent(int value) {
            if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) {
                return this;
            } else if (this.left != null && value < this.value) {
                return this.left.searchParent(value);
            } else if (this.right != null && value > this.value) {
                return this.right.searchParent(value);
            }
            return null;
        }

        /**
         * 添加节点
         *
         * @param node 待添加的节点
         */
        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 midOrder() {
            if (this.left != null) {
                this.left.midOrder();
            }
            System.out.println(this);
            if (this.right != null) {
                this.right.midOrder();
            }
        }
    }

    private Node root;

    /**
     * 调用节点内部类中封装的查询节点方法
     *
     * @param value 要删除的值
     * @return 如果在当前二叉树中存在当前元素,则返回节点;否则,返回 null
     */
    public Node search(int value) {
        if (root == null) {
            return null;
        } else {
            return root.search(value);
        }
    }

    /**
     * 调用节点内部类中封装的查询父节点方法
     *
     * @param value 要删除的值
     * @return 如果在当前二叉树中存在当前元素节点的父节点,则返回父节点;否则,返回 null
     */
    public Node searchParent(int value) {
        if (root == null) {
            return null;
        } else {
            return root.searchParent(value);
        }
    }

    /**
     * 删除当前节点右子树最小值节点并返回最小值
     *
     * @param node 要删除的节点
     * @return 待删除节点右子树最小值节点的值
     */
    public int delRightTreeMin(Node node) {
        Node target = node;
        while (target.left != null) {
            target = target.left;
        }
        //调用删除节点方法,只是让其父节点的左/右子节点的引用指向空
        //该节点实际仍存在
        delNode(target.value);
        return target.value;
    }

    /**
     * 删除节点
     *
     * @param value 待删除的值
     */
    public void delNode(int value) {
        if (root == null) {
            System.out.println("当前二叉树为空!无法进行删除操作!");
        } else {
            Node targetNode = search(value);
            //如果待删除节点为空(即二叉树中没有找到该节点),结束方法
            if (targetNode == null) {
                return;
            }
            //如果上一步条件判断没有结束方法,则说明在二叉树中找到了该节点
            //此时如果根节点的左右子节点均为空,则该节点就是根节点
            //直接将根节点置空,即删除该节点
            if (root.left == null && root.right == null) {
                root = null;
                return;
            }
            Node parentNode = searchParent(value);
            //待删除节点的左右子树均为空,即为叶子节点
            if (targetNode.left == null && targetNode.right == null) {
                //如果当前节点为其父节点的左/右子节点,则直接通过其父节点删除
                if (parentNode.left != null && parentNode.left.value == value) {
                    parentNode.left = null;
                } else if (parentNode.right != null && parentNode.right.value == value) {
                    parentNode.right = null;
                }
                //如果待删除节点的左右子树均不为空,即为有两棵子树的节点
            } else if (targetNode.left != null && targetNode.right != null) {
                //找到并删除其右子树的最小值节点
                //并将该节点的值赋给当前节点
                targetNode.value = delRightTreeMin(targetNode.right);
                //除去上述两种情况,即为有一棵子树的节点
            } else {
                //判断当前节点的子节点为左子节点还是右子节点
                if (targetNode.left != null) {
                    //如果其父节点为空,则当前节点即为根节点
                    //直接执行 else,将子节点赋给根节点
                    if (parentNode != null) {
                        //判断当前节点是其父节点的左子节点还是右子节点
                        //然后通过父节点删除
                        if (parentNode.left == targetNode) {
                            parentNode.left = targetNode.left;
                        } else {
                            parentNode.right = targetNode.left;
                        }
                    } else {
                        root = targetNode.left;
                    }
                } else {
                    //如果其父节点为空,则当前节点即为根节点
                    //直接执行 else,将子节点赋给根节点
                    if (parentNode != null) {
                        //判断当前节点是其父节点的左子节点还是右子节点
                        //然后通过父节点删除
                        if (parentNode.left == targetNode) {
                            parentNode.left = targetNode.right;
                        } else {
                            parentNode.right = targetNode.right;
                        }
                    } else {
                        root = targetNode.right;
                    }
                }
            }
        }
    }

    /**
     * @param node 添加节点
     */
    public void add(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.add(node);
        }
    }

    /**
     * 中序遍历
     */
    public void midOrder() {
        if (root == null) {
            System.out.println("当前二叉树为空!无法进行中序遍历!");
        } else {
            root.midOrder();
        }
    }
}

测试结果:

中序遍历二叉树:
Node{value=-23}
Node{value=-2}
Node{value=3}
Node{value=7}
Node{value=9}
Node{value=45}
删除叶子节点:
Node{value=-23}
Node{value=-2}
Node{value=3}
Node{value=9}
Node{value=45}
删除只有一棵子树的节点:
Node{value=-23}
Node{value=3}
Node{value=9}
Node{value=45}
删除有两棵子树的节点:
Node{value=-23}
Node{value=3}
Node{value=45}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值