二叉搜索树

/**
 * 二叉搜索树(算法导论)
 * 实现 遍历、查询、新增、删除、最大值查找、最小值查找、获取后继节点
 */
public class SearchBinaryTree {

    /**
     * 中序遍历所有节点
     * 伪代码:
     * INORDER-TREE-WALK(x)
     *  if(x != NIL)
     *      INORDER-TREE-WALK(x.left)
     *      print x.key
     *      INORDER-TREE-WALK(x.right)
     */
    public static  void inPrint( TreeNode root){
        if(root !=null){
            inPrint(root.left);
            System.out.println(root.val);
            inPrint(root.right);
        }
    }

    /**
     * 输入二叉搜索树的根节点root 和需要查询的关键字key,查找key对应的节点
     * 伪代码(递归实现):
     * TREE-SEARCH(X,K)
     *  if x == NIL or k ==x.key
     *      return x
     *  if k<x.key
     *      return TREE-SEARCH(X.left,K)
     *  else return TREE-SEARCH(X.right,K)
     * @param root 根节点
     * @param key 关键字
     * @return
     */
    public static TreeNode searchByRecursion( TreeNode root, int key){
        if(root == null || key == root.val){
            return root;
        }
        if(key <root.val) {
            return  search(root.left, key);
        }else{
            return  search(root.right, key);
        }
    }

    /**
     * 输入二叉搜索树的根节点root 和需要查询的关键字key,查找key对应的节点
     * 伪代码(非递归实现):
     * ITERATIVE-TREE-SEARCH(X,K)
     *  while x != NIL and k !=x.key
     *      if k < x.key
     *          x = x.left
     *      else x = x.right
     *  return x
     * @param root 根节点
     * @param key 关键字
     * @return
     */
    public static TreeNode search( TreeNode root, int key){
        while (root != null && key != root.val){
            if(key <root.val) {
                root = root.left;
            }else{
                root = root.right;
            }
        }
        return root;
    }

    /**
     * 查找最小值(二次搜索树最小值为最左节点)
     * 伪代码:
     * TREE-MINNUM(X)
     *  while x.left != NIL
     *      X = x.left
     *  return x
     * @param root
     * @return
     */
    public static TreeNode getMin(TreeNode root){
        while (root.left!=null){
            root = root.left;
        }
        return root;
    }

    /**
     * 查找最大值(二次搜索树最大值为最右节点)
     * 伪代码:
     * TREE-MAXNUM(X)
     *  while x.right != NIL
     *      X = x.right
     *  return x
     * @param root
     * @return
     */
    public static TreeNode getMax(TreeNode root){
        while (root.right!=null){
            root = root.right;
        }
        return root;
    }

    /**
     * 获取后继节点
     * 伪代码:
     * TREE-SUCCESSOR(x)
     *  if x.right != NIL
     *      return TREE-SUCCESSOR(x.right)
     *  y = x.p
     *  while y!=NIL and x == y.right
     *      x = y
     *      y = y.p
     *  return y
     * @param node
     * @return
     */
    public  static  TreeNode getNext (TreeNode node){
        TreeNode next = null;
        if(node.right != null){
            return getNext(node.right);
        }
        next = node.p;
        while (next != null && node==next.right){
            node = next;
            next = next.p;
        }
        return next;
    }

    /**
     * 将一个新值插入到二叉树中
     * 伪代码:
     * TREE-INSERT(T,z)
     *  y = NIL
     *  x = T.root
     *  while x != NIL
     *      y = x
     *      if z.key < x.key
     *          x = x.left
     *      else x = x.right
     *  z.p = y
     *  if y == NIL
     *      T.root = z
     *  elseif z.key < y.key
     *      y.left = z
 *      else y.right = z
     * 代码逻辑:
     * 先找到需要挂载的节点
     * 再判断挂哪边
     * @param root 根节点
     * @param val 需要插入的值
     * @return
     */
    public static void  insert (TreeNode root, int val){
        TreeNode  insertNode= new TreeNode(val);
        if(root == null) {
            return;
        }
        TreeNode node = root;
        TreeNode temp = null;
        while ( node != null ){
            temp  = node;
            if(val < node.val){
                node = node.left;
            }else {
                node = node.right;
            }
        }
        insertNode.p = temp;  //挂载父节点

        if(val<temp.val){
            temp.left = insertNode;
        } else {
            temp.right = insertNode;
        }
    }

    /**
     * 删除一个节点,删除成功返回true,删除失败返回false
     * 伪代码:
     * TREE-DELETE(T,z)
     *  if z.left == NIL
     *      TRANSPLANT(T,z,z.right)
     *  elseif z.right == NIL
     *      ss(T,z,z.left)
     *  else y = TREE-MINIMUN(z.right)
     *      if y.p != z
     *          TRANSPLANT(T,y,y.right)
     *          y.right = z.right
     *          y.right.p = y
     *      TRANSPLANT(T,z,y)
     *      y.left = z.left
     *      y.left.p = y
     * 代码逻辑:
     * 1.如果z没有子节点,直接删除
     * 2.如果z只有一个子节点,子节点直接替换z
     * 3.如果有两个子节点,那么找z的后继y(一定在右子树中),并让y占据z在树中的位置。z的左、右子树挂载到y上
     * 4.如果z没有左孩子,用右孩子替换z
     * 5.如果z仅有一个左孩子,左孩子直接替换z
     * @param root
     * @param node
     * @return
     */
    public static void  delete (TreeNode root, TreeNode node){
        TreeNode temp = null;
        if(node.left == null){
            tranSplant(root,node,node.right);
        }else if (node.right == null){
            tranSplant(root,node,node.left);
        }else {
            temp = getMin(node.right);
            if(temp.p!=node){
                tranSplant(root,temp,temp.right);
                temp.right = node.right;
                temp.right.p = temp;
            }
            tranSplant(root,node,temp);
            temp.left = node.left;
            temp.left.p = temp;
        }
        node = null;
    }

    /***
     * 移动子树
     * TRANSPLANT(T,u,v)
     * if u.p == NIL
     *  T.root = v
     * elseif u == u.p.left
     *  u.p.left = v
     * else u.p.right = v
     * if v!= NIL
     *  v.p = u.p
     * @param root
     * @param u
     * @param v
     */
    private static  void  tranSplant(TreeNode root,TreeNode u,TreeNode v){
        if(u.p == null){
            root = v;
        }else if (u==u.p.left){
            u.p.left = v;
        }else {
            u.p.right = v;
        }
        if(v != null){
            v.p = u.p;
        }

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值