ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BST(二叉搜索树)原理解析及代码实现

2022-01-27 19:06:23  阅读:134  来源: 互联网

标签:结点 null return target BST value 二叉 else 解析


文章目录

简介

二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势

二叉搜索树介绍

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

二叉搜索树是能够高效地进行如下操作的数据结构

  1. 插入一个数值
  2. 查询是否包含某个数值
  3. 删除某个数值

在二叉搜索树中:

  1. 若任意结点的左子树不空,则左子树上所有结点的值均不大于它的根结点的值。
  2. 若任意结点的右子树不空,则右子树上所有结点的值均不小于它的根结点的值。
  3. 任意结点的左、右子树也分别为二叉搜索树。

比如数据(7,3,10,12,5,1,9),对应的二叉排序树为
在这里插入图片描述

再次基础上插入2:
在这里插入图片描述

二叉树的中序遍历

在这里插入图片描述
如上图 中序遍历(先输出左子节点然后是当前节点最后是右节点)后的输出为:
1,2,3,5,7,9,10,12
为递增序列

代码:

Node节点中的方法:(以便于在tree中调用)

public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }

        System.out.println(this);

        if (this.right != null) {
            this.right.infixOrder();
        }
    }

在二叉搜索树中的中序遍历:

 public void infixOrder(){
       if (root!=null){
           root.infixOrder();
       }else {
           System.out.println("树为空,无法遍历");
       }
    }

插入结点

插入结点比较简单,主要逐个比较要插入结点,与当前结点的值的大小即可,如果小于当前结点的值。就继续往左边找,大于等于往右边找;

代码:
Node结点中的add代码

 //添加结点的方法
    public void add(Node node) {
        if (node == null) {
            return;
        }

        if (node.getData() < this.getData()) {
            //如果小就往左边插入
            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);
            }
        }

    }

BinarySortTree 中的插入结点的代码:

public void add(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.add(node);
        }
    }

删除结点

  • 叶子节点:直接删除,不影响原树。

思路:
1.首先找到需要删除的结点 targetNode
2.找到targetNode的父节点parent
3.根据targetNode是parent结点的左子节点还是右子结点
4.根据对应的情况进行删除
如果是parent的左子节点:parent.left = null;
如果是parent的右子节点:parent.right = null;

  • 仅仅有左或右子树的节点:节点删除后,将它的左子树或右子树整个移动到删除节点的位置就可以,子承父业。

思路:
1.首先找到需要删除的结点 targetNode
2.找到targetNode的父节点parent
3.根据targetNode是parent结点的左子节点还是右子结点
4.1如果是parent的左子节点
如果target.left=null,那么令parent.left = target.right即可
如果target.right = null,那么令parent.left = target.left即可
4.2如果是parent的右子节点
如果target.left=null,那么令parent.right = target.right即可
如果target.right = null,那么令parent.right = target.left即可

  • 既有左又有右子树的节点:找到须要删除的节点p的直接前驱或者直接后继s,用s来替换节点p,然后再删除节点s。

思路:
上面我们可以直到中序遍历的结果是一个升序的输出,那么我们是不是可以找一个结点代替这个要删除的结点,找那个了,就找输出序列根target相邻的结点,即左子树的最大值,或者右子树的最小值,具体是那个?你如果你插入值得时候相同得值放在右子树,那么删除得时候就找左子树得最大值,反之亦然。
1.首先找到需要删除的结点 targetNode
2.找到targetNode的父节点parent
3.从target得左子树或者右子树找到代替得点
4.用一个临时变量保存这个结点
5.然后删除这个结点
6.令target.value = temp.value即可

代码实现:

Node中得查找目标结点,查找父节点

  //查找要删除的结点
    public Node search(int value) {

        //如果要查找的值等于当前结点的值 则直接返回
        if (this.getData() == value) {
            return this;
        }

        //如果不是当前值,并且要查找的值小于当前结点的值 则往左边进行查找
        if (value < this.data) {
            //如果左结点不为空 则向左查找
            if (this.getLeft() != null) {
                return this.getLeft().search(value);
            } else {//为空则直接返回null 即没找到
                return null;
            }
        } else {//在右边查找
            //右子结点不为空 在右边查找
            if (this.getRight() != null) {
                return this.getRight().search(value);
            } else {
                return null;
            }
        }

    }

    //得到要删除结点的父节点
    public Node searchParent(int value) {
        //如果要删除的是根节点  逻辑在tree中处理即可
        //如果当前结点的子结点就是要删除的结点  则直接返回
        if ((this.left != null && this.left.data == value) || (this.right != null && this.right.data == value)) {
            return this;
        } else {
            //如果查找的值 小于当前结点的值 就向左边查找
            if (value < this.data && this.left != null) {
                return this.left.searchParent(value);
            } else if (value >= this.data && this.right != null) {//向右
                return this.right.searchParent(value);
            } else {
                return null;
            }
        }

    }

BinarySortTree中得删除代码:

public void deleteNode(int value){
        //如果数为空 则直接结束
        if (root==null){
            return;
        }

        //首先得到目标结点

        Node target = search(value);
        //如果没有找到  则直接结束
        if (target==null){
            return;
        }

        //如果二叉树只有根节点 说明待删除的结点就是根节点
        if (root.getLeft()==null && root.getRight()==null){
            root = null;
            return;
        }

        //得到父节点 开始删除

        Node parent = searchParent(value);

        if (target.getLeft()==null && target.getRight()==null){//需要删除得是叶子结点
            //进行判断需要删除得结点得父结点

            if (parent.getLeft()==target){
                parent.setLeft(null);
            }else {
                parent.setRight(null);
            }
        }else if (target.getLeft()!=null && target.getRight()!=null){//有两个结点得时候
            int min = GetMaxNode(target.getLeft());

            target.setData(min);


        }else {//删除单节点

            //如果删除得是左子树
            if (target.getLeft()!=null){
                if (parent!=null){
                    if (parent.getLeft()==target){
                        parent.setLeft(target.getLeft());
                    }else {
                        parent.setRight(target.getLeft());
                    }
                }else {
                    root = target.getLeft();
                }

            }else {//删除右子树

                if (parent!=null){
                    if (parent.getLeft()==target){
                        parent.setLeft(target.getRight());
                    }else {
                        parent.setRight(target.getRight());
                    }
                }else {
                    root = target.getRight();
                }
            }

        }




    }

    //得到当前子树得最小值

    private  int GetMaxNode(Node node){
        Node target =node;
        while (target.getRight()!=null){
            target = target.getRight();
        }

        deleteNode(target.getData());

        return target.getData();
    }

    //得到需要删除的结点
    private Node search(int value){
        if (root == null){
            return null;
        }
        return root.search(value);
    }

    //得到需要删除的父节点
    private Node searchParent(int value){
        if (root!=null){
            if (value==root.getData()){
                return null;
            }else {
                return root.searchParent(value);
            }
        }
        return null;
    }

完整代码:

Node结点:

package binarysorttree;

/**
 * @ClassName: Node
 * @Author
 * @Date 2022/1/25
 */
public class Node {
    private int data;
    private Node left;
    private Node right;

    //构造方法
    public Node(int data) {
        this.data = data;
    }

    //添加结点的方法
    public void add(Node node) {
        if (node == null) {
            return;
        }

        if (node.getData() < this.getData()) {
            //如果小就往左边插入
            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 Node search(int value) {

        //如果要查找的值等于当前结点的值 则直接返回
        if (this.getData() == value) {
            return this;
        }

        //如果不是当前值,并且要查找的值小于当前结点的值 则往左边进行查找
        if (value < this.data) {
            //如果左结点不为空 则向左查找
            if (this.getLeft() != null) {
                return this.getLeft().search(value);
            } else {//为空则直接返回null 即没找到
                return null;
            }
        } else {//在右边查找
            //右子结点不为空 在右边查找
            if (this.getRight() != null) {
                return this.getRight().search(value);
            } else {
                return null;
            }
        }

    }

    //得到要删除结点的父节点
    public Node searchParent(int value) {
        //如果要删除的是根节点  逻辑在tree中处理即可
        //如果当前结点的子结点就是要删除的结点  则直接返回
        if ((this.left != null && this.left.data == value) || (this.right != null && this.right.data == value)) {
            return this;
        } else {
            //如果查找的值 小于当前结点的值 就向左边查找
            if (value < this.data && this.left != null) {
                return this.left.searchParent(value);
            } else if (value >= this.data && this.right != null) {//向右
                return this.right.searchParent(value);
            } else {
                return null;
            }
        }

    }

    //中序遍历

    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }

        System.out.println(this);

        if (this.right != null) {
            this.right.infixOrder();
        }
    }

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

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    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;
    }
}

BinarySortTree代码:

package binarysorttree;



/**
 * @ClassName: BinarySortTree
 * @Author
 * @Date 2022/1/25
 */
public class BinarySortTree {

    Node root = null;

    public void add(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.add(node);
        }
    }



    public void deleteNode(int value){
        //如果数为空 则直接结束
        if (root==null){
            return;
        }

        //首先得到目标结点

        Node target = search(value);
        //如果没有找到  则直接结束
        if (target==null){
            return;
        }

        //如果二叉树只有根节点 说明待删除的结点就是根节点
        if (root.getLeft()==null && root.getRight()==null){
            root = null;
            return;
        }

        //得到父节点 开始删除

        Node parent = searchParent(value);

        if (target.getLeft()==null && target.getRight()==null){//需要删除得是叶子结点
            //进行判断需要删除得结点得父结点

            if (parent.getLeft()==target){
                parent.setLeft(null);
            }else {
                parent.setRight(null);
            }
        }else if (target.getLeft()!=null && target.getRight()!=null){//有两个结点得时候
            int min = GetMaxNode(target.getLeft());

            target.setData(min);


        }else {//删除单节点

            //如果删除得是左子树
            if (target.getLeft()!=null){
                if (parent!=null){
                    if (parent.getLeft()==target){
                        parent.setLeft(target.getLeft());
                    }else {
                        parent.setRight(target.getLeft());
                    }
                }else {
                    root = target.getLeft();
                }

            }else {//删除右子树

                if (parent!=null){
                    if (parent.getLeft()==target){
                        parent.setLeft(target.getRight());
                    }else {
                        parent.setRight(target.getRight());
                    }
                }else {
                    root = target.getRight();
                }
            }

        }




    }

    //得到当前子树得最小值

    private  int GetMaxNode(Node node){
        Node target =node;
        while (target.getRight()!=null){
            target = target.getRight();
        }

        deleteNode(target.getData());

        return target.getData();
    }

    //得到需要删除的结点
    private Node search(int value){
        if (root == null){
            return null;
        }
        return root.search(value);
    }

    //得到需要删除的父节点
    private Node searchParent(int value){
        if (root!=null){
            if (value==root.getData()){
                return null;
            }else {
                return root.searchParent(value);
            }
        }
        return null;
    }




    public void infixOrder(){
       if (root!=null){
           root.infixOrder();
       }else {
           System.out.println("树为空,无法遍历");
       }
    }




}

测试代码:

package binarysorttree;

/**
 * @ClassName: Test
 * @Author
 * @Date 2022/1/25
 */
public class Test {
    public static void main(String[] args) {
        BinarySortTree bs = new BinarySortTree();

        int[] arr =  {7,7,3,10,12,5,1,9};

        for (int i : arr){
            bs.add(new Node(i));
        }

        System.out.println("插入后");
        bs.infixOrder();

        bs.deleteNode(7);
        bs.deleteNode(3);
        bs.deleteNode(10);
        bs.deleteNode(12);
        bs.deleteNode(5);
        bs.deleteNode(1);
        bs.deleteNode(9);
        bs.deleteNode(9);
        System.out.println("-----------------");

        System.out.println("删除后");

        bs.infixOrder();


    }
}

结果:
在这里插入图片描述

标签:结点,null,return,target,BST,value,二叉,else,解析
来源: https://blog.csdn.net/qq_45795744/article/details/122714692

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有