二叉搜索树java实现

二叉搜索树java实现

public class a {

    public static void main(String[] args) {
        SearchBinaryTree s = new SearchBinaryTree(null,0);
        int[] array = new int[]{50, 30, 80, 20, 35, 34, 32, 40, 70, 75, 100};
        for (int i = 0; i < array.length; i++) {
            s.add(array[i]);
        }

        //二叉搜索树 中序遍历
        inorder(s.root);
        s.delete(70);
        System.out.println();
        inorder(s.root);

    }


    public static void inorder(Node root) {
        if (root != null) {
            inorder(root.leftChild);
            System.out.print(root.val+"-");
            inorder(root.rightChild);
        }
    }

}
class SearchBinaryTree{

    public Node root;
    private int size;

    public SearchBinaryTree(Node root, int size) {
        this.root = root;
        this.size = size;
    }


    public boolean add(int val) {

        //先判断父节点是否初始化
        if (root == null) {
            root = new Node(val);
            size++;
            return true;
        }
        //父节点已经初始化  则需要找到需要插入的合适的父节点

        Node node = findFatherNode(root,val);
        Node childNode = new Node(val);
        //找到父节点之后  与父节点值比较
        if (val < node.val) {
            node.leftChild = childNode;
            childNode.parent = node;
        } else if (val > node.val) {
            node.rightChild = childNode;
            childNode.parent = node;
        } else {
            //相等
            return false;
        }
        size++;
        return  true;
    }

    /**
     * 找到精要插入的合适的父节点
     *  递归写法,需要分别对节点的左右子树,先写临界返回
     *  临界返回有几种情况,
     *  1、父节点为空
     *  2、父节点的左右子树分别为空
     *  3、父节点就是叶子节点
     *  4、插入节点值与父节点相等
     */
    public Node findFatherNode(Node node, int val) {

        //1、父节点为空
        if (node== null) {
            return node;
        }

        //2、父节点的左右子树分别为空
        if (val < node.val && node.leftChild == null) {
            return node;
        }
        if (val > node.val && node.rightChild == null) {
            return node;
        }

        //3、父节点就是叶子节点
        if (node.leftChild == null && node.rightChild == null) {
            return node;
        }
        //左右子树分别递归遍历
        if (val < node.val && node.leftChild != null) {
            return findFatherNode(node.leftChild, val);
        } else if (val > node.val && node.rightChild != null) {
            return findFatherNode(node.rightChild, val);
        } else {
            //4、插入节点值与父节点相等
            return node;
        }
    }

    //循环迭代版本
    public boolean put(int val) {
        //先判断父节点是否初始化
        if (root == null) {
            root = new Node(val);
            size++;
            return true;
        }

        Node temp = root;
        Node fatherNode;
        int t;
        do {
            fatherNode = temp;
            t =temp.val - val;
            if (t > 0) {
                temp = temp.leftChild;
            } else if (t < 0) {
                temp = temp.rightChild;
            } else {
                temp.val = val;
                return false;
            }
        } while (temp != null);

        Node childNode = new Node(fatherNode, val);
        if (t > 0) {
            fatherNode.leftChild = childNode;
        } else if (t < 0) {
            fatherNode.rightChild = childNode;
        }
        return true;
    }


    //删除节点

    /**
     * 删除节点有几种情况
     * 1、删除的节点没有左右子节点
     * 2、删除的节点只有左节点,没有右节点
     * 3、删除的节点只有右节点,没有左节点
     * 4、删除的节点既有左节点,又有右节点
     * 针对第四种情况,需要找到该节点的后继节点,将此节点替换为后继节点
     * 后继节点 :大于该节点值得所有节点集合中值最小的那个节点,即为后继节点,当然,也有可能不存在后继节点。
     * 如果后继节点存在的情况下,它一定在其(右子树的左子节点中)(没有右子树的话可能是右子节点)
     * 后继节点有一个特点,因为他大于某一个节点的最小值,所以他一定没有左子节点,所以针对第四种情况,先将后继节点与要删除的
     * 节点替换,然后删除后继节点(后继节点没有左子节点,跟1、3种情况是一样,直接删除)
     */
    public boolean delete(int val) {

        Node node = getNode(val);
        if (node == null) {
            return Boolean.FALSE;
        }

        //第四种情况,左右节点都存在
        if (node.leftChild != null && node.rightChild != null) {
            //找到后继节点  将该节点替换为后继节点
            Node successor = getSuccessor(node);
            //值替换
            node.val = successor.val;
            node = successor;
        }
        //注意  这个时候后继节点还没删除    node此时就是后继节点
        //下面就是相当于删除某一个节点 ,可能是1、2、3情况
        Node child;
        if (node.leftChild != null ) {
            child = node.leftChild;
        } else {
            child = node.rightChild;
        }
        if (child != null) {
            child.parent = node.parent;
        }

        //如果要删除节点的父节点为空,则要删除父节点
        if (node.parent == null) {
            this.root = child;
        } else if (node == node.parent.leftChild) {
            node.parent.leftChild = child;
        } else if (node == node.parent.rightChild) {
            node.parent.rightChild = child;
        }
        return Boolean.TRUE;
    }

    public Node getNode(int val) {
        if (root == null) return null;
        Node temp = root;
        do {
            if (val > temp.val) {
                temp = temp.rightChild;
            } else if (val < temp.val) {
                temp = temp.leftChild;
            } else {
                return temp;
            }
        } while (temp != null);
        return null;
    }

    /**
     * 获取后继节点
     * 1、先判断该节点有没有右子树,如果有,则从右节点的左子树中寻找后继节点,没有则进行下一步
     * 2、
     * @param node
     * @return
     */
    public Node getSuccessor(Node node) {
        if (node == null) return null;
        //后继节点存在于右子树中
        Node p = node.rightChild;
        if (p != null) {
            while(p.leftChild != null) {
                p = p.leftChild;
            }
            return p;
        }

        //如果该节点没有右子节点,则从其父节点中,祖父节点的右子树中寻找
        //则查找"x的最低的父结点,并且该父结点要具有左孩子(最低的父节点)
        //目标节点是存在与后继节点的左子树中,如下,找4的后继节点
        //4 没有有子树,可以从他的父节点中找,但是4又是其父节点的右孩子,比父节点大,不符合后继节点要求,继续向上找
        //直到找到父节点为左孩子位置,这样该父节点的值就一定小于它的父节点,而且目标节点是存在于它的子孩子中的
        //这样即可找到后继节点
        /**
         *          6
         *        /   \
         *       1     7
         *        \
         *         5
         *        /
         *       3
         *      / \
         *     2   4
         *        /
         *      3.5
         */
        while (node.parent != null && node == node.parent.rightChild) {
            node = node.parent;
        }
        return node.parent;
    }

    /**
     * 将子节点替换为父节点
     * @param fatherNode
     * @param childNode
     */
    public void transplant(Node fatherNode, Node childNode) {
        /*
           需要判断父节点是否为root节点
           如果父节点不是root节点,需要判断父节点是左子节点还是右子节点,
           这样才能准确将childNode放到准确位置
         */
        //父节点的父节点为空的话  就是root节点
        if (fatherNode.parent == null) {
            this.root = childNode;
        } else if (fatherNode.parent.leftChild == fatherNode) {
            fatherNode.parent.leftChild = childNode;
        } else if (fatherNode.parent.rightChild == fatherNode) {
            fatherNode.parent.rightChild = childNode;
        }

        if (childNode != null) {
            childNode.parent = fatherNode.parent;
        }
    }
}

class Node{

     Node parent;
     Node leftChild;
     Node rightChild;
     int val;

    public Node(Node parent, Node leftChild, Node rightChild, int val) {
        this.parent = parent;
        this.leftChild = leftChild;
        this.rightChild = rightChild;
        this.val = val;
    }

    public Node(int val){
        this(null,null,null,val);
    }

    public Node(Node node,int val){
        this(node,null,null,val);
    }

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值