二叉排序树的 增&删&改&查

相信大家对二叉树并不陌生,今天我们一起来学习一下 一个特殊的二叉树 —二叉排序树。
先来看百度给出的标准的定义:

一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
(2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的节点。

说的是非常的好,但是我一句没看懂,简单来说就是有序的二叉树,今天我们一起来实现它的增删改查

注意:下面实例中的代码是相关连的,可能会有调用,一定要看清楚o

数据定义

public class Node_tree {
    private int val;            //数据
    private Node_tree lch;//左子树
    private Node_tree rch;//右子树
    public int getVal() {
        return val;
    }
    public void setVal(int val) {
        this.val = val;
    }
    public Node_tree getLch() {
        return lch;
    }
    public void setLch(Node_tree lch) {
        this.lch = lch;
    }
    public Node_tree getRch() {
        return rch;
    }
    public void setRch(Node_tree rch) {
        this.rch = rch;
    }
    /**
     * 定义构造方法
     */
    public Node_tree(){}
    public Node_tree(int n){
        this.val = n;
    }
    }

1、二叉排序树的添加

这个添加的方法很好懂,比如要插入一个数,从已经存在的二叉树的根节点可是判断,如果比节点的值大,则继续向其右子树进行比较,如果比节点的值小,则向其左子树进行比较,依次递归

    /**
     * 定义添加数据的方法,这不是静态方法,树的根节点调用,传入要插入节点
     */
    public void add(Node_tree t){
        //如果t的val值比这个节点的val值大,则往这个节点的右子树添加,不过前提是,右子树没有值,否则执行递归
        if(t.getVal()>val){
            if(rch==null){
                rch=t;
            }else{
                rch.add(t);
            }
        }else{
        //如果t的val值比这个节点的val值小,则往这个节点的左子树添加,不过前提是,左子树没有值,否则执行递归
            if(lch==null){
                lch=t;
            }else{
                lch.add(t);
            }
        }
    }

2、二叉排序树的删除

我个人认为删除操作是最难的操作,里面用到的方法很多

(1)定义一个方法,传入一个树和一个数,如果这个数在这个树中,则返回这个数的节点对象

    /**
     * 查询某个数字的函数,返回值为这个数字的节点对象
     * @param  n 树的根节点,要查询的数字
     */
    public static Node_tree check(Node_tree tree,int n){
        Node_tree ndb = tree;
        if(n>tree.val){
            if(tree.getRch()!=null){
                return ndb=check(tree.getRch(),n);
            }else{
                System.out.println("没有这个数");
            }
        }else if(n<tree.val){
            if (tree.getLch()!=null){
                return ndb = check(tree.getLch(),n);
            }else{
                System.out.println("没有这个数");
            }
        }else{
            System.out.println("找到啦");
            return ndb;
        }
        return ndb;
    }

(2)因为删除操作需要,需要获得待删除节点的父亲节点,已经考虑根节点

  /**
     * 定义一个方法,找到一个节点的父节点,传入一个树的根节点和要找的孩子节点的value值
     */
    public static Node_tree getparent(Node_tree node,int child){
        Node_tree parent  = new Node_tree();
        while (node!=null){
            if(node.getVal() == child){
                break;
            }
            parent = node;
            if (child<node.getVal()){
                node = node.getLch();
            }else{
                node = node.getRch();
            }
        }
        return parent;
    }

(3)定义一个方法,来找到指定节点右子树中最小的数对应的节点,这一步非常重要,所以我将其单拿出来写,返回的节点就是用来替换待删除节点的,为后面提到的后继节点

    /**
     * 定一个方法,找到其右子树中最小的数,返回节点对象,s输入要查询的树就行
     */
    public static Node_tree right_min(Node_tree tree){
        Node_tree ndb = new Node_tree();
        ndb = tree.rch;
        while(ndb.getLch()!=null){
            ndb=ndb.getLch();
        }
        return ndb ;
    }

下面才真正开始进行删除操作
删除节点分为三种情况:
1、待删除节点有两个子节点
2、待删除节点有一个子节点
3、待删除节点没有子节点
*第二第三种情况可以放在一起说

步骤:
2.1、待删除节点有一个或者零个子节点
找到其右子树中最小的数对应的节点 作为后继节点— 》找到待删除节点的父亲节点—》判断待删除节点是父亲节点的左子树还是右子树—》将父亲节点对应的子节点指针指向后继节点

  public static  void del_one(Node_tree thisNode,Node_tree parent){
        if(thisNode.getVal()>parent.getVal()){
            //待删除节点是父节点的右子节点
            if(thisNode.getRch()!=null){
                parent.setRch(thisNode.getRch());
            }else if(thisNode.getLch()!=null){
                parent.setRch(thisNode.getLch());
            }else{
                parent.setRch(null);
            }
        }else{
            //待删除节点是父节点的左子节点
            if(thisNode.getRch()!=null){
                parent.setRch(thisNode.getRch());
            }else if(thisNode.getLch()!=null){
                parent.setRch(thisNode.getLch());
            }else{
                parent.setLch(null);
            }
        }
    }

2.2待删除节点有两个子节点
步骤:
找到后继节点(此处后继节点是右子树中最小的,所以一定没有左子树)—》找到后继节点的父亲节点p2—>先将后继节点的值赋给待删除节点—》让后继节点与其父亲节点进行同 2.1 的删除操作

    public static void del(Node_tree node,int n){
        //找到这个节点
        Node_tree thisNode = check(node,n);
        //找到这个节点的父节点
        Node_tree parent = getparent(node,n);
        //1、这个节点不存在的话,结束方法
        if(thisNode == null){
            return;
        }
        if(thisNode.getLch()!=null&&thisNode.getRch()!=null){
            //待删除节点左右子节点都有
            Node_tree rm = right_min(thisNode);
            //获得这个后继节点的父亲
            Node_tree rm_par = getparent(node,rm.getVal());
            //将这个后继节点的值给待删除节点
            thisNode.setVal(rm.getVal());
            //对这个后继节点进行删除,因为它肯定是只有单个子节点或者没有
            del_one(rm,rm_par);
            return;
        }else{
//            2、待删除节点有一个子节点
//             3、待删除节点没有子节点
            del_one(thisNode,parent);
        }
    }

3、二叉排序树的改

这个修改是最简单操作的,基本思想就是想删除你想替换的节点,再添加你想要的更换为的数的节点

   /**
     * 修改函数,这 就简单啦,就是先进行删除节点,再插入节点
     * 传入 修改的树,和要修改的数,修改为的数
     */
    public  static void update(Node_tree node,int n1,int n2){
        //先将原来的数删除
        del(node,n1);
        //将n2插入
        Node_tree n2node = new Node_tree(n2);
        node.add(n2node);
    }

4、二叉排序树的查

这里的查找函数没有准备很多,因为二叉排序树中,左子树<节点<右子树,所以利用中序查询是最好的方法,能让其有序输出

    public void midtravl(){
        if (lch!=null){
            lch.midtravl();

        }
        System.out.println(val);
        if (rch!=null){
            rch.midtravl();
        }
    }
发布了71 篇原创文章 · 获赞 14 · 访问量 5613

猜你喜欢

转载自blog.csdn.net/flying_hengfei/article/details/102644910