利用java写一个有各种操作的二叉搜索树

下面是代码,各种功能完成方法组

/**
 * 实现一个二叉搜索树
 *
 * 使用者: 数据容器
 * 数据结构:  二叉搜索树(特殊的二叉树)
 * 底层结构: 链表
 */
public class MyBSTree <T extends Comparable<T>> {

    private Node root; // 我们持有的树的根节点
    private int size;

    /**
     * 二叉搜索树的添加方法
     * @param value : 要添加的内容
     * @return: 添加是否成功
     */
    public boolean add(T value) {
        // 判断存储的内容是否为null: null没有办法比较大小
        if (value == null){
            throw new IllegalArgumentException("parame is null");
        }

        // 树是否为空 --> 添加元素就是根节点
        if (isEmpty()){
            root = new Node(value);
            size++;
            return true;
        }

        // 树不空 : 比较大小找到添加位置(遍历) --> 添加

        Node mid = root; // 定义一个遍历结点
        Node midF = null; // 用来记录遍历结点的父结点
        int com = -1;

        while (mid != null){
            // 让当前遍历结点存储的内容和 要存储的内容 比较大小
            com = mid.value.compareTo(value);

            if (com < 0){
                // 意味着value值比当前遍历结点大, 如果要存储, 用该存储到mid的right方法
                midF = mid;
                mid = mid.right;

            } else if (com > 0){
                // 意味着value值比当前遍历结点小, 如果要存储, 用该存储到mid的left方法
                midF = mid;
                mid = mid.left;

            }else {
                // 当前遍历的结点, 和要存储的值, 一样大
                // 如果在一个二叉搜索树, 添加的数据重复了, 在理论上有三种常见的处理手法
                // 1, 计数法
                // 2, 拉链法
                // 3, 修正的BSTree

                // 实际操作的时候, 我们一般不允许添加重复元素
                return false;
            }
        }

        // 上述循环走完
        if (com > 0){
            midF.left = new Node(value);
        } else {
            midF.right = new Node(value);
        }
        size++;

        return true;
    }


    /**
     * 二叉搜索树的删除方法
     * @param value : 要删除的内容
     * @return : 删除是否成功
     */
    public boolean remove(T value){
        // 判断参数是否为null, 二叉搜索树不允许存储null
        if (value == null){
            throw new IllegalArgumentException("parame is null");
        }
        // 二叉搜索树是否为空
        if (isEmpty()){
            throw new RuntimeException("tree is empty");
        }

        // 先根据提供value找到这个值, 是三种情况

        Node mid = root; // 定义一个遍历结点
        Node midF = null;

        while (mid != null){
            int com = value.compareTo(mid.value);

            if (com < 0){
                // 这个查找的值比mid当前遍历结点要小, 如果存在在left方向
                midF = mid;
                mid = mid.left;
            }else if (com > 0){
                // 这个查找的值比mid当前遍历结点要大, 如果存在在right方向
                midF = mid;
                mid = mid.right;
            }else {
                // 当前遍历的mid就是要找的value值 --- 相等
                break;
            }
        }

        // 上述循环, 有两个跳出条件
        // 1, mid == null -> 没有存储这个数据
        // 2, 找到了, mid是要删除的内容

        if (mid == null){
            // 没有存储这个数据
            return false;
        }

        // 先判断这个要删除的结点mid是不是双分支
        if (mid.left != null && mid.right != null){
            // 左右孩子都有, 是双分支 --> 先替换再删除
            // 选right的最小值   --> 选取right子树的最left结点

            // 先标记right子树根节点
            Node min = mid.right;
            Node minF = mid;

            // 在right子树上, 向left移动
            while (min.left != null){
                minF = min;
                min = min.left;
            }

            // min 就是要找的right子树的最小值 ---> 替换
            mid.value = min.value;

            // min就是替换结点
            // minF就是替换结点的父结点

            mid  = min;
            midF = minF;
        }


        // 处理要么是叶子, 要么是单分支
        Node ch = mid.left != null ? mid.left : mid.right;

        // 特殊情况
        if (midF == null){
            // 如果只有一个根结点, 要删除的还是根节点
            // 根节点是一个单分支,  要删除的还是根节点
            root = ch;
            size--;
            return true;
        }


        if (midF.left == mid){
            midF.left = ch;
        }else {
            midF.right = ch;
        }
        size--;
        return true;
    }


    // ----------------------------------------------------------
    // 层级遍历
    public List<T>  leOrder(){

//        MyDBLinkedList<T> tMyDBLinkedList = new MyDBLinkedList<>();
//        List<T> list = new LinkedList<>();
        LinkedList<T> list = new LinkedList<>();


        // 创建一个队列
        MyArrayQueue<Node> queue = new MyArrayQueue<>();
        // 1, 把根节点入队列
        queue.offer(root);
        // 2, 循环: 队列不空
        while (!queue.isEmpty()){

            // 出队列一个元素
            Node poll = queue.poll();
            // 遍历
            list.add(poll.value);
            // 左右孩子入队列
            if (poll.left != null){
                queue.offer(poll.left);
            }
            if (poll.right != null){
                queue.offer(poll.right);
            }

        }

        return list;
    }

    // 前序遍历

    // 后序遍历
    public List<T> postOrder(){
        // 存储遍历结果的容器
        List<T> list = new LinkedList<>();

        // 创建一个栈
        MyArrayStack<Node> stack = new MyArrayStack<>();
        // 1, 根节点入栈
        stack.push(root);

        // 2, 循环: 栈不空
        while (!stack.isEmpty()){
            // 出栈元素
            Node pop = stack.pop();
            // 头插法遍历
            list.add(0, pop.value);

            // 把出栈结点左右子结点入栈
            if (pop.left != null){
                stack.push(pop.left);
            }
            if (pop.right != null){
                stack.push(pop.right);
            }

        }

        return list;
    }
    //后序遍历
    public List<T> postOrder2(){
        List<T> list = new LinkedList<>();
        postOrder2(root, list);
        return list;
    }
    // 后序遍历的递归方法
    private void postOrder2(Node node, List<T> list){
        // 出口
        if (node == null){
            return;
        }

        // 左  右  根
        postOrder2(node.left, list);// 遍历左子树
        postOrder2(node.right, list);// 遍历右子树
        list.add(node.value);// 遍历当前的根
    }


    // 中序遍历
    public List<T> inOrder(){
        // 创建一个容器, 保存遍历结果
        List<T> list = new LinkedList<>();

        // 栈
        MyArrayStack<Node> stack = new MyArrayStack<>();
        // 标记结点
        Node mid = root;

        // 循环: 栈不空  或者 标记结点不是null
        while (!stack.isEmpty()  || mid != null){
            // 标记结点left序列全入栈
            while (mid != null){
                stack.push(mid);
                mid = mid.left;
            }
            // 出栈一个元素
            Node pop = stack.pop();
            // 遍历
            list.add(pop.value);

            // 标记结点指向出栈元素的right孩子
            mid = pop.right;
        }


        return list;
    }
    //中序遍历
    public List<T> inOrder2(){
        List<T> list = new LinkedList<>();
        inOrder2(root, list);
        return list;
    }
    // 中序遍历的递归方法
    private void inOrder2(Node node, List<T> list){
        // 出口
        if (node == null){
            return;
        }

        // 左 根 右
        inOrder2(node.left, list);// 遍历左子树
        list.add(node.value);// 遍历当前的根
        inOrder2(node.right, list);// 遍历右子树
    }




    // 前序+中序建树
    // 中序+后序建树:

    public void  buildTreeByInAndPostOrder(List<T> inOrder, List<T> postOrder){

        root = buildTreeByInAndPostOrder2(inOrder, postOrder);
        size = inOrder.size();
    }

    /**
     * 根据中序和后序递归建树
     * @param inOrder : 给定的中序
     * @param postOrder: 给定的后序
     * @return : 根据中序和后序,建成的树的根节点
     */
    private Node buildTreeByInAndPostOrder2(List<T> inOrder, List<T> postOrder) {
        // 出口
        if (inOrder.isEmpty()){
            return null;
        }
        if (inOrder.size() == 1){
            return new Node(inOrder.get(0));
        }


        // 先获得根结点
        T value = postOrder.get(postOrder.size() - 1);

        // 获得根结点在中序中的位置
        int index = inOrder.indexOf(value);


        // left子树:
        //         中序: 0 - index -1
        //         后序: 0 - index -1

        // right子树
        //        中序: index+1   ~ size -1
        //         后序: index ~  size -2

        // 从原本的中序和后序中切割出, left子树的中序和后序
        List<T> listLeftInOrder = inOrder.subList(0, index);
        List<T> listLeftPostOrder = postOrder.subList(0, index);
        // 根据 left子树的中序和后序  --> 递归构建left子树
        Node left = buildTreeByInAndPostOrder2(listLeftInOrder, listLeftPostOrder);

        // 从原本的中序和后序中切割出, right子树的中序和后序
        List<T> listRightInOrder = inOrder.subList(index+1,  inOrder.size());
        List<T> listRightPostOrder = postOrder.subList(index, postOrder.size() -1);

        // 根据 right子树的中序和后序  --> 递归构建right子树
        Node right = buildTreeByInAndPostOrder2(listRightInOrder, listRightPostOrder);


        // 构建当前的根节点
        Node node = new Node(value, left, right);

        return node;
    }


    public boolean isEmpty() {
        return size == 0;
    }


    class Node{
        T value; // 值域
        Node left ;// 左指针域
        Node right; // 右指针域


        public Node(T value) {
            this.value = value;
        }
        public Node(T value, Node left, Node right) {
            this.value = value;
            this.left = left;
            this.right = right;
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赤狐先生

如果有一点点帮助,可以给点支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值