二叉搜索树

目录

1搜索树

1.1 概念

1.2查找操作

1.3插入操作

1.4删除操作(难点)

1.4.1如果该树为空(也就是根节点==null),直接return;

1.4.2找到要删除的节点以及该节点的父节点

1.4.3找到需要删除的节点时,讨论删除的多种情况

1.4.3.1目标节点的左孩子节点为空 ------cur.left == null

1.4.3.2目标节点的右孩子节点为空 ------cur.right == null

1.4.3.3目标节点的左右孩子节点均不为空

2.二叉搜索树的完整代码:


1搜索树

1.1 概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

●若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

●若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

●它的左右子树也分别为二叉搜索树

二叉搜索树中不存在两个值一样的节点

int[] array ={5,3,4,1,7,8,2,6,0,9};

1.2查找操作

在二叉搜索树中,严格遵守每一个节点的左子树中的值都比该子树的根节点值小,右子树中的值都比该子树的根节点大

所以我们每次查找时,拿要查找的值和节点比较,如果比节点的值小,我们用cur指向该节点的左孩子节点,否则指向该节点的右孩子节点

    public boolean search(int val){
        TreeNode cur=root;
        while(cur!=null){
            if(cur.val>val){
                cur=cur.left;
            }else if (cur.val<val){
                cur=cur.right;
            }else {
                return true;
            }
        }
    return false;
    }

故我们在查找节点时,用val值与每一个节点的值进行比较,如果val值比该节点值小,我们就往该节点的左孩子节点走,否则往该节点的右孩子节点走,直到val值与节点值相同,返回true,如果走到null都没有找到val,那么就返回false

1.3插入操作

如果树为空,即根==null,直接插入

  if(root==null){
            root=new TreeNode(key);
            return;
        }

2.如果树不是空树,按照查找逻辑确定插入位置,插入新节点

        TreeNode node=new TreeNode(key);
        TreeNode prv=null;//用prv记录插入节点的上一个节点
        TreeNode cur=root;
        while(cur!=null){//循环找到插入节点的位置
            if(key<cur.val){//如果当前节点的值大于key值,就往当前节点的左孩子节点走,先让prv指向当前节点,再让cur往左孩子节点走
                prv=cur;
                cur=cur.left;
            }else if(key> cur.val){//如果当前节点的值小于key值,就往当前节点的右孩子节点走,先让prv指向当前节点,再让cur往右孩子节点走
                prv=cur;
                cur=cur.right;
            }else {//如果key值与当前节点的val值相等,就直接返回,这是因为一棵二叉搜索树中不能存在两个值一样的节点
                return;
            }
        }
//找到了插入位置,在让key的值比上一个节点prv的值做比较,如果key大于prv的val值,就让key的节点插入到prv的右孩子节点,如果key小于prv的val值,就让key的节点插入到prv的左孩子节点
        if(prv.val>key){
            prv.left=node;
        }else{
            prv.right=node;
        }

定义两个TreeNode变量,cur用来查找需要插入的位置,prv用来记录cur的上一个节点,当cur为null时,prv就为要插入位置的上一个节点,所以循环条件为cur!=null

在循环中:

1.如果当前节点的值大于key值,就往当前节点的左孩子节点走,先让prv指向当前节点,再让cur往左孩子节点走

2.如果当前节点的值小于key值,就往当前节点的右孩子节点走,先让prv指向当前节点,再让cur往右孩子节点走

3.如果key值与当前节点的val值相等,就直接返回,这是因为一棵二叉搜索树中不能存在两个值一样的节点

4.找到了插入位置,在让key的值比上一个节点prv的值做比较,如果key大于prv的val值,就让key的节点插入到prv的右孩子节点,如果key小于prv的val值,就让key的节点插入到prv的左孩子节点(比较确认新节点应该插入到prv的左孩子节点还是右孩子节点)

1.4删除操作(难点)

1.4.1如果该树为空(也就是根节点==null),直接return;

       if(root==null){
            return;
        }

1.4.2找到要删除的节点以及该节点的父节点

TreeNode prv=null;
TreeNode cur=root;
while(cur!=null){
    if(cur.val>val){
        prv=cur;
        cur=cur.left;
    }else if(cur.val<val){
        prv=cur;
        cur=cur.right;
    }else {
        break;
    }
}
if(cur==null){
    return;
}

该操作和上面的查找操作一样,定义两个TreeNode变量,prv指向cur的父节点,cur去循环查找目标节点,查找到了就直接跳出循环,判断一下cur是否为空,如果为空,直接return;

1.4.3找到需要删除的节点时,讨论删除的多种情况

1.4.3.1目标节点的左孩子节点为空 ------cur.left == null

设待删除结点为 cur, 待删除结点的双亲结点为 prv

1. cur 是 root,则 root = cur.right

        //要删除节点的左子树为空
if(cur.left==null){
    //节点为根节点
    if(cur==root){
        root=cur.right;
    }

2. cur 不是 root,cur 是 parent.left,则 prv.left = cur.right

if(cur==prv.left){
        prv.left=cur.right;
    }

3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.right

 if(cur==prv.right){
        prv.right=cur.right;
    }
1.4.3.2目标节点的右孩子节点为空 ------cur.right == null

1. cur 是 root,则 root = cur.left

 if(cur.right==null){
            if(cur==root){
                root=cur.left;
            } 

2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.left

if (cur==prv.left) {
                prv.left=cur.left;
            }

3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.left

 prv.right=cur.left;

注:在讨论目标节点的左右孩子节点到底谁为空时,已经包含了左右孩子节点都为空的情况,故接下来只需要讨论目标节点左右孩子均不为空

1.4.3.3目标节点的左右孩子节点均不为空

目标节点的左子树的最右边节点的值时左子树中最大的,却比右子树中的值都要小,所以将其与目标节点交换,然后按右子树为空删除该节点

亦或者是,找到目标节点的右子树的最左端的节点,因为这个节点是右子树中值最小的节点,却比左子树的所有值都打,将目标节点与其交换,然后按左子树为空删除

上图以左子树中的最大值为例

            TreeNode p=cur;
    TreeNode c=cur.left;
    while(c.right!=null){
        p=c;
        c=c.right;
    }
swap(c,cur);
   if(c==p.left){
       p.left=c.left;
   }
   if(c==p.right){
       p.right=c.left;
   }

因为左子树的最大值可能是目标节点的左孩子节点,所以需要判断一下左子树最大节点与去父节点的关系,如果他是其父节点的左孩子节点,就让其父节点的左孩子节点变为该节点的左孩子节点,否则其父节点的右孩子节点变为该节点的左孩子节点

2.二叉搜索树的完整代码:

package Binary;

import com.sun.source.tree.Tree;

public class BinarySearchTree {
    static class TreeNode{
        public int val;
        public TreeNode left;
        public TreeNode right;


        public TreeNode(int val) {
            this.val = val;
        }
    }

    public TreeNode root;

    public void insert(int key){
        if(root==null){
            root=new TreeNode(key);
            return;
        }
        TreeNode node=new TreeNode(key);
        TreeNode prv=null;
        TreeNode cur=root;
        while(cur!=null){
            if(key<cur.val){
                prv=cur;
                cur=cur.left;
            }else if(key> cur.val){
                prv=cur;
                cur=cur.right;
            }else {
                return;
            }
        }
        if(prv.val>key){
            prv.left=node;
        }else{
            prv.right=node;
        }



    }

    public boolean search(int val){
        TreeNode cur=root;
        while(cur!=null){
            if(cur.val>val){
                cur=cur.left;
            }else if (cur.val<val){
                cur=cur.right;
            }else {
                return true;
            }
        }
    return false;
    }

    public  void remove(int val){
        if(root==null){
            return;
        }

TreeNode prv=null;
TreeNode cur=root;
while(cur!=null){
    if(cur.val>val){
        prv=cur;
        cur=cur.left;
    }else if(cur.val<val){
        prv=cur;
        cur=cur.right;
    }else {
        break;
    }
}
if(cur==null){
    return;
}
removeNode(prv,cur);
    }

    private void removeNode(TreeNode prv,TreeNode cur){
        //要删除节点的左子树为空
if(cur.left==null){
    //节点为根节点
    if(cur==root){
        root=cur.right;
    }else if(cur==prv.right){
        prv.right=cur.right;
    } else{
        prv.left=cur.right;
    }
}

//要删除节点的右子树为空
        else   if(cur.right==null){
            if(cur==root){
                root=cur.left;
            } else if (cur==prv.left) {
                prv.left=cur.left;
            }else {
                prv.right=cur.left;
            }
        }
        //要删除的节点两边都不为空
        else {
            TreeNode p=cur;
    TreeNode c=cur.left;
    while(c.right!=null){
        p=c;
        c=c.right;
    }
swap(c,cur);
   if(c==p.left){
       p.left=c.left;
   }
   if(c==p.right){
       p.right=c.left;
   }
        }
    }

private void swap(TreeNode v1,TreeNode v2){
        int tmp= v1.val;
        v1.val=v2.val;
        v2.val=tmp;
}


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值