二叉搜索树(BST)的查找(分为递归和迭代),创建,插入,删除

1.二叉搜索树的概念

        二叉搜索树又称二叉排序树,它有如下性质:

                1.若左子树不为空,左子树上的所有节点的key值都小于根节点。

                2.若右子树不为空,右子树上的所有节点的key值都大于根节点。

                3.中序遍历可以得到有序序列。

                4.不存在key值相同的节点。

2.二叉搜索树的意义

        我们知道链表插入,删除很方便,只需要修改指针的指向,但是查找很麻烦,需要从头节点开始遍历,相反,数组的插入,删除很麻烦,需要挪动后面所有元素,但是查找很简单,直接使用下标来索引,所以综合二者优点的二叉搜索树诞生了,BST查找快,插入,删除和操作链表一样方便。

3.二叉搜索树的创建

        先按升序排好序,每次把中间的元素当作根节点,依次递归下去就能构架一颗BST,举个例子:[1,2,3,4,5,6,7,9,10,14],

数组中间元素5就是根节点。还是上图吧:


java代码如下:

private static TreeNode build(int[] num,TreeNode root0,int left,int right)   //递归创建二叉排序树
    {
        if (left>right)
        {
            return null;
        }
        int mid=(left+right)/2;
        root0=new TreeNode(num[mid]);
        root0.left=build(num,root0.left,left,mid-1);
        root0.right=build(num,root0.right,mid+1,right);
        return root0;
    }
public static TreeNode createTree(int[] num)
    {
        Arrays.sort(num);
        TreeNode root=null;
        return build(num,root,0,num.length-1);
    }

4.二叉搜索树的查找

public static TreeNode search0(TreeNode root, int key)   //递归实现搜索
    {
        if (root==null)
        {
            return null;   //说明没有这个key
        }
        if (root.data==key)
        {
            return root;
        }
        if (root.data>key)   //key在root的左子树
        {
            return search0(root.left,key);
        }
        return search0(root.right,key);   //key在root的右子树
    }

    public static TreeNode search1(TreeNode root,int key)   //非递归实现搜索
    {
        TreeNode cur;
        for (cur=root;cur!=null&&cur.data!=key;)
        {
            cur=cur.data>key?cur.left:cur.right;
        }
        return cur;
    }

5.二叉搜索树的插入

public static Boolean insert(TreeNode root,TreeNode node)   //插入节点,递归实现
    {
        if (root.data==node.data)
        {
            return false;
        }
        if (root.data<node.data)
        {
            if (root.right==null)
            {
                root.right=node;
            }
            else
            {
                return insert(root.right,node);
            }
        }
        else if (root.data>node.data)
        {
            if (root.left==null)
            {
                root.left=node;
            }
            else
            {
                return insert(root.left,node);
            }
        }
        return true;
    }

6.二叉搜索树的删除

        删除节点是相当的麻烦,需要考虑边边角角。

        粗略分为下面四种情况:

            1.要删除的节点只有左孩子,直接把左孩子代替被删除节点

            2.要删除的节点只有右孩子,直接把右孩子代替被删除节点

            3.要删除的节点左右孩子均有,找到被欲删除节点的后继节点(后面会将什么是后继节点),用后继节点代替被删除节点

            4.节点左右孩子都没有的情况可以归为1,2,不需要单独写代码

        后继节点就是欲删除节点的右子树的最左边节点(通俗说,就是从欲删除节点的右孩子开始,中序遍历的第一个节点就是后继节点)上一张算法导论的插图(ps:从别人那里扣来的^_^):


Talk is cheap,Show code!

 public static TreeNode delete(TreeNode root,int key)   //删除节点
    {
        TreeNode parent=null;
        TreeNode cur=root;
        while (cur!=null&&cur.data!=key)
        {
            parent=cur;
            cur=cur.data>key?cur.left:cur.right;
        }
        if (cur==null)
        {
            return null;
        }
        if (cur.left==null)   //欲删除节点只有右子树
        {
            if (parent==null)  //欲删除节点是根节点
            {
                return cur.right;
            }
            if (parent.left==cur)   //欲删除节点是其父节点的左子树
            {
                parent.left=cur.right;
            }
            else                   //否则是其右子树
            {
                parent.right=cur.right;
            }
        }
        else if (cur.right==null)   //欲删除节点只有左子树
        {
            if (parent==null)  //欲删除节点是根节点
            {
                return cur.left;
            }
            if (parent.left==cur)   //欲删除节点是其父节点的左子树
            {
                parent.left=cur.left;
            }
            else                   //否则是其右子树
            {
                parent.right=cur.left;
            }
        }


        else                   //欲删除节点有左右子树
        {
            TreeNode tmp=cur.right;   //找到右子树最左边节点(右子树中序遍历第一个节点)也叫后继节点
            TreeNode tmp_parent=cur;  //后继节点的父节点
            while (tmp.left!=null)
            {
                tmp_parent=tmp;
                tmp=tmp.left;
            }

            tmp.left=cur.left;
            if (tmp.right!=null)   //若后继节点有右子树
            {
                if (tmp_parent!=cur)   //排除欲删除节点刚好是其后继节点的父节点
                {
                    tmp_parent.left=tmp.right;   //后继节点右子树代替后继节点成为其父节点的左子树
                    tmp.right=cur.right;
                }
            }

            if (parent==null)   //欲删除节点是根节点
            {
                return tmp;
            }
            else if (parent.right==cur)  //欲删除节点是其父节点的右子树
            {
                parent.right=tmp;
            }
            else                         //欲删除节点是其父节点的左子树
            {
                parent.left=tmp;
            }
        }
        return root;
    }

7.完整代码如下:

package search;

/**
 * Created by 灵魂都在冒香气的神 on 2018/2/24.
 */
public class TreeNode
{
    public int data;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int num)
    {
        data=num;
    }
    public TreeNode()
    {
    }
}
package search;

import java.util.Arrays;

/**
 * Created by 灵魂都在冒香气的神 on 2018/2/24.
 * 二叉搜索树
 */
public class BinarySearch
{
    public static TreeNode createTree(int[] num)
    {
        Arrays.sort(num);
        TreeNode root=null;
        return build(num,root,0,num.length-1);
    }


    public static TreeNode search0(TreeNode root, int key)   //递归实现搜索
    {
        if (root==null)
        {
            return null;   //说明没有这个key
        }
        if (root.data==key)
        {
            return root;
        }
        if (root.data>key)   //key在root的左子树
        {
            return search0(root.left,key);
        }
        return search0(root.right,key);   //key在root的右子树
    }

    public static TreeNode search1(TreeNode root,int key)   //非递归实现搜索
    {
        TreeNode cur;
        for (cur=root;cur!=null&&cur.data!=key;)
        {
            cur=cur.data>key?cur.left:cur.right;
        }
        return cur;
    }

    public static Boolean insert(TreeNode root,TreeNode node)   //插入节点
    {
        if (root.data==node.data)
        {
            return false;
        }
        if (root.data<node.data)
        {
            if (root.right==null)
            {
                root.right=node;
            }
            else
            {
                return insert(root.right,node);
            }
        }
        else if (root.data>node.data)
        {
            if (root.left==null)
            {
                root.left=node;
            }
            else
            {
                return insert(root.left,node);
            }
        }
        return true;
    }

    public static TreeNode delete(TreeNode root,int key)   //删除节点
    {
        TreeNode parent=null;
        TreeNode cur=root;
        while (cur!=null&&cur.data!=key)
        {
            parent=cur;
            cur=cur.data>key?cur.left:cur.right;
        }
        if (cur==null)
        {
            return null;
        }
        if (cur.left==null)   //欲删除节点只有右子树
        {
            if (parent==null)  //欲删除节点是根节点
            {
                return cur.right;
            }
            if (parent.left==cur)   //欲删除节点是其父节点的左子树
            {
                parent.left=cur.right;
            }
            else                   //否则是其右子树
            {
                parent.right=cur.right;
            }
        }
        else if (cur.right==null)   //欲删除节点只有左子树
        {
            if (parent==null)  //欲删除节点是根节点
            {
                return cur.left;
            }
            if (parent.left==cur)   //欲删除节点是其父节点的左子树
            {
                parent.left=cur.left;
            }
            else                   //否则是其右子树
            {
                parent.right=cur.left;
            }
        }


        else                   //欲删除节点有左右子树
        {
            TreeNode tmp=cur.right;   //找到右子树最左边节点(右子树中序遍历第一个节点)也叫后继节点
            TreeNode tmp_parent=cur;  //后继节点的父节点
            while (tmp.left!=null)
            {
                tmp_parent=tmp;
                tmp=tmp.left;
            }

            tmp.left=cur.left;
            if (tmp.right!=null)   //若后继节点有右子树
            {
                if (tmp_parent!=cur)   //排除欲删除节点刚好是其后继节点的父节点
                {
                    tmp_parent.left=tmp.right;   //后继节点右子树代替后继节点成为其父节点的左子树
                    tmp.right=cur.right;
                }
            }

            if (parent==null)   //欲删除节点是根节点
            {
                return tmp;
            }
            else if (parent.right==cur)  //欲删除节点是其父节点的右子树
            {
                parent.right=tmp;
            }
            else                         //欲删除节点是其父节点的左子树
            {
                parent.left=tmp;
            }
        }
        return root;
    }

    private static TreeNode build(int[] num,TreeNode root0,int left,int right)   //递归创建二叉排序树
    {
        if (left>right)
        {
            return null;
        }
        int mid=(left+right)/2;
        root0=new TreeNode(num[mid]);
        root0.left=build(num,root0.left,left,mid-1);
        root0.right=build(num,root0.right,mid+1,right);
        return root0;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值