首页 > 其他分享 >二叉排序树(BST树)

二叉排序树(BST树)

时间:2022-11-22 10:56:51浏览次数:34  
标签:结点 null BST value 二叉 targetNode right 排序 left

二叉排序树(BST树)

一、介绍

二叉排序树: 所有叶子结点都要求左子结点比当前结点小,右子结点比当前结点大。

优点:查询速度,新增结点速度都会更快。每判断一个结点,都会选择去往左子树或右子树继续比较。从这点看,比链表效率要更高。

二、代码实现

2.1 添加结点(add())

/**
     *  递归形式添加结点
     * @param node 我们要添加到二叉排序树中的结点
     */
    public void add(Node node){
        if (node == null){
            System.out.println("node为空,无法添加");
            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);
            }
        }

    }

2.2 删除结点(delete())

思路:

  1. 先找到需要删除的结点(targetNode)位置。
  2. 找到targetNode的父结点(parent)。
  3. 确定target是parent的左子结点还是右子结点。
  4. 根据前面的结果,我们来分类实现删除:

 1. 要删除的结点是叶子结点,无子结点:
    1.1 target是parent的左子结点:parent.left = null;
    1.2 target是parent的右子结点:parent.right = null;
 2. 删除有一个子结点的结点:
    2.1 确定targetNode的子结点是左子结点还是右子结点:
    2.2 根据不同情况,使用不同方法进行删除:
         2.2.1. targetNode 有左子结点:
            · targetNode是parent的左子结点:parent.left = targetNode.left;
            · targetNode是parent的右子结点:parent.right = targetNode.left;
         2.2.2. targetNode 有右子结点:
            · targetNode是parent的左子结点:parent.left = targetNode.right;
            · targetNode是parent的右子结点:parent.right = targetNode.right;
 3. 删除有两个子结点的结点:
    3.1 先找到需要删除的结点(targetNode)位置。
    3.2 找到targetNode的父结点(parent)。
    3.3 从targetNode的右子树中找到最小的结点。(也可以是左子树中最大的结点)
    3.4 用一个临时变量temp,保存最小结点的值。
    3.5 用最小结点的值,替换掉我们想要删除掉的结点。
    3.6 通过parent删除掉右子树最小的结点:parent.left/right = null;

代码:
(1) binarySortTree

//查找要删除的结点
    public Node search(int value){
        if (root == null){
            return null;
        }else {
            return root.search(value);
        }
    }

    //查找要删除结点的父结点
    public Node searchParent(int value){
        if (root == null){
            return null;
        }else {
            return root.searchParent(value);
        }
    }

    /**
     *  要删除的结点(两个子结点)的右子树中最小的结点的值
     * @param node 右子树的根结点
     * @return 返回以node 为根结点的二叉排序树中最小的结点的值
     */
    public int delRightTreeMin(Node node){
        Node targetNode = node;
        while (targetNode.left != null){ // 一直查找左子结点,就可以找到最小的结点
            targetNode = targetNode.left;
        }
        //现在 targetNode 指向了最小的结点
        // 删除掉这个结点
        delNode(targetNode.value);
        return targetNode.value;
    }

    // 删除结点
    public void delNode(int value){
        if (root == null){
            return;
        }else {
            // 1. 先查找到该结点
            Node targetNode = root.search(value);
                // 如果没找到要删除的结点,返回null
            if (targetNode == null){
                return;
            }
                // 如果我们发现当前这颗二叉树只有一个结点
            if (root.left == null && root.right == null){
                root = null;
                return;
            }
            // 2. 查找到要删除结点的父结点
            Node parentNode = root.searchParent(value);

            // 3. 开始分类进行删除结点

            // 3.1 叶子结点
            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){ // 有两个子结点的结点
                // 找到右子树中最小的结点的值,并将这最小的结点删除
                int min = delRightTreeMin(targetNode.right);
                targetNode.value = min;
            } else { // 有一个子结点的结点
                //如果要删除的结点有左子结点
                if (targetNode.left != null){
                    if (parentNode != null) {
                        if (parentNode.left.value == value) {
                            parentNode.left = targetNode.left;
                        } else {
                            parentNode.right = targetNode.left;
                        }
                    }else {
                        root = targetNode.left;
                    }
                }else { // 如果要删除的结点有右子结点
                    if (parentNode != null) {
                        if (parentNode.left.value == value) {
                            parentNode.left = targetNode.right;
                        } else {
                            parentNode.right = targetNode.right;
                        }
                    }else {
                        root = targetNode.right;
                    }
                }
            }
        }
    }

(2) Node

/**
     *  查找要删除掉的结点
     * @param value 要删除的结点的值
     * @return 返回要删除的那个结点
     */
    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);
        }
    }

    /**
     *  查找父结点
     * @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 (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; // 没有找到对应父结点
            }
        }
    }

2.3 总代码

二叉排序树 中序遍历,输出结果刚好是从小到大 顺序

package main.com.lrf.binarusorttree;

import java.lang.reflect.Parameter;

public class BinarySortTreeDemo {
    public static void main(String[] args) {
        int[] arr = {7,3,10,12,5,1,9,2};
        BinarySortTree binarySortTree = new BinarySortTree();
        // 循环添加结点到二叉排序树
        for (int i = 0; i < arr.length; i++) {
            binarySortTree.add(new Node(arr[i]));
        }

        //中序遍历
        System.out.println("开始中序遍历输出该二叉排序树");
        binarySortTree.infixOrder();  // 二叉排序树 中序遍历,输出结果刚好是从小到大 顺序。

//        System.out.println("删除叶子节点 “2” ");
//        binarySortTree.delNode(2);

//        System.out.println("删除一个子结点的结点: “1” ");
//        binarySortTree.delNode(1);

        System.out.println("删除两个子结点的结点: “7”");
        binarySortTree.delNode(7);
        binarySortTree.infixOrder();



    }
}


class BinarySortTree{
    private Node root;


    //查找要删除的结点
    public Node search(int value){
        if (root == null){
            return null;
        }else {
            return root.search(value);
        }
    }

    //查找要删除结点的父结点
    public Node searchParent(int value){
        if (root == null){
            return null;
        }else {
            return root.searchParent(value);
        }
    }

    /**
     *  要删除的结点(两个子结点)的右子树中最小的结点的值
     * @param node 右子树的根结点
     * @return 返回以node 为根结点的二叉排序树中最小的结点的值
     */
    public int delRightTreeMin(Node node){
        Node targetNode = node;
        while (targetNode.left != null){ // 一直查找左子结点,就可以找到最小的结点
            targetNode = targetNode.left;
        }
        //现在 targetNode 指向了最小的结点
        // 删除掉这个结点
        delNode(targetNode.value);
        return targetNode.value;
    }

    // 删除结点
    public void delNode(int value){
        if (root == null){
            return;
        }else {
            // 1. 先查找到该结点
            Node targetNode = root.search(value);
                // 如果没找到要删除的结点,返回null
            if (targetNode == null){
                return;
            }
                // 如果我们发现当前这颗二叉树只有一个结点
            if (root.left == null && root.right == null){
                root = null;
                return;
            }
            // 2. 查找到要删除结点的父结点
            Node parentNode = root.searchParent(value);

            // 3. 开始分类进行删除结点

            // 3.1 叶子结点
            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){ // 有两个子结点的结点
                // 找到右子树中最小的结点的值,并将这最小的结点删除
                int min = delRightTreeMin(targetNode.right);
                targetNode.value = min;
            } else { // 有一个子结点的结点
                //如果要删除的结点有左子结点
                if (targetNode.left != null){
                    if (parentNode != null) {
                        if (parentNode.left.value == value) {
                            parentNode.left = targetNode.left;
                        } else {
                            parentNode.right = targetNode.left;
                        }
                    }else {
                        root = targetNode.left;
                    }
                }else { // 如果要删除的结点有右子结点
                    if (parentNode != null) {
                        if (parentNode.left.value == value) {
                            parentNode.left = targetNode.right;
                        } else {
                            parentNode.right = targetNode.right;
                        }
                    }else {
                        root = targetNode.right;
                    }
                }
            }
        }
    }


    //添加结点的方法
    public void add(Node node){
        //判断root是否为空
        if (root == null){ //root 为空, 使root 指向 node
            root = node;
        }else { // root不为空,调用结点的ad方法进行递归添加
            root.add(node);
        }
    }

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


class  Node {
    int value;
    Node left;
    Node right;

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

    /**
     *  递归形式添加结点
     * @param node 我们要添加到二叉排序树中的结点
     */
    public void add(Node node){
        if (node == null){
            System.out.println("node为空,无法添加");
            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();
        }
    }

    /**
     *  查找要删除掉的结点
     * @param value 要删除的结点的值
     * @return 返回要删除的那个结点
     */
    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);
        }
    }

    /**
     *  查找父结点
     * @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 (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; // 没有找到对应父结点
            }
        }
    }

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

标签:结点,null,BST,value,二叉,targetNode,right,排序,left
From: https://www.cnblogs.com/xm-lrf/p/16914379.html

相关文章

  • 每日算法之二叉树中和为某一值的路径(一)
    JZ82二叉树中和为某一值的路径(一)代码packageesay.JZ82二叉树中和为某一值的路径1;importjava.util.*;classTreeNode{intval=0;TreeNodeleft=......
  • 数组部分基础&冒泡排序
    数组基础知识 1.数组的创建格式:变量(数组)类型变量(数组)名=变量(数组)值int[]nums;//声明一个数组nums=newint[10];//创建一个数组int[]nums=new......
  • 二叉树
    01.二叉搜索树的最近公共祖先235.二叉搜索树的最近公共祖先当我们从上向下去递归遍历,第一次遇到cur节点是数值在[p,q]区间中,那么cur就是p和q的最近公共祖先;当前节......
  • 冒泡排序法
    voidBubbleSort(ints[],intn){//函数参数:数组与数组大小 inti,j,temp; for(i=0;i<n-1;i++)//从0开始进行n-1轮排序 {......
  • LC[199] 二叉树的右视图
    [199]二叉树的右视图题目链接:https://leetcode.cn/problems/binary-tree-right-side-view/description/WA一开始的想法是遍历二叉树,只需要右分枝即可。但是如果右边没......
  • 33. 搜索旋转排序数组
    整数数组 nums 按升序排列,数组中的值 互不相同 。在传递给函数之前,nums 在预先未知的某个下标 k(0<=k<nums.length)上进行了 旋转,使数组变为 [nums[k],nums[k+......
  • 【算法】Java解答有序链表转换二叉搜索树,从中序与后序遍历序列构造二叉树
    有序链表转换二叉搜索树给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差......
  • 页面点击按钮实现排序
    思路:用ajax实现局部div元素更新,新写一个要更新div部分的html页面modelsclassArticle(models.Model):title=models.CharField(max_length=100,verbose_nam......
  • 数组去重排序
    letdata=[{key:"01",value:"压缩",},{key:"02",value:"永恩",},{key:"03",value:"压缩",},{key:"04",value:"卢锡安",},]......
  • js对后端传递的三维扁平化数组排序
    [{Col:2,Row:3,Lay:1},{Col:1,Row:1,Lay:1},{Col:1,Row:2,Lay:4}] 简略数据格式如上,用sort方法排序data.Result.sort((a,b)=>{if(a.Row!==b.Row){retu......