Java实现: 二叉搜索树非递归/递归增删查,栈和递归实现前中后序遍历,队列实现层级遍历,递归根据前中序值或中后序值建树

该代码实现了一个二叉搜索树(BST),包括非递归和递归方式的增删查操作,以及前中后序遍历。此外,还提供了根据前序和中序遍历值重建二叉树的功能。代码中使用栈实现了各种遍历方法,并提供了层级遍历。测试部分展示了如何使用这些功能。
摘要由CSDN通过智能技术生成
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/*
二叉搜索树非递归/递归实现增删查,递归/栈实现前中后序遍历,队列实现层级遍历,递归根据前中序值或中后序值建树
 */
//测试
class MyBSTDemo {
    public static void main(String[] args) {
        MyBST<Integer> myBST = new MyBST<>();
        List<Integer> inOrder = new ArrayList<>();
        inOrder.add(-8);
        inOrder.add(-4);
        inOrder.add(-2);
        inOrder.add(-1);
        inOrder.add(3);
        inOrder.add(5);
        inOrder.add(6);
        inOrder.add(7);
        inOrder.add(15);
        inOrder.add(20);
        List<Integer> preOrder = new ArrayList<>();
        preOrder.add(5);
        preOrder.add(-4);
        preOrder.add(-8);
        preOrder.add(-1);
        preOrder.add(-2);
        preOrder.add(3);
        preOrder.add(15);
        preOrder.add(6);
        preOrder.add(7);
        preOrder.add(20);
        myBST.piBuildBST(preOrder, inOrder);//调用建树的方法
        System.out.println(myBST.inOrder_Stack());
        myBST.removeD(7);
        myBST.addD(7);
        System.out.println(myBST.inOrder_Stack());
//        myBST.add(5);
//        myBST.add(15);
//        myBST.add(-4);
//        myBST.add(-1);
//        myBST.add(-8);
//        myBST.add(3);
//        myBST.add(6);
//        myBST.add(20);
//        myBST.add(7);
//        myBST.add(-2);
//        myBST.remove(5);
//        System.out.println(myBST.preOrder_Stack());
//        System.out.println(myBST.inOrder_Stack());
//        System.out.println(myBST.postOrder_Stack());
//        System.out.println(myBST.preOrder());
//        System.out.println(myBST.inOrder());
//        System.out.println(myBST.PostOrder());
//        myBST.contains(5);
//        myBST.remove(5);
    }
}

public class MyBST<T extends Comparable<T>> {
    private Node root;
    private int size;

    public int size() {
        return size;
    }

    /**
     * 判断树是否为空的方法
     *
     * @return true 树为空
     */
    public boolean isEmpty() {
        return size == 0 || root == null;
    }

    /**
     * 添加一个值的节点的方法
     *
     * @param t 要添加的节点的值
     * @return true 添加成功
     */
    public boolean add(T t) {
        if (t == null) throw new IllegalArgumentException("param is null");
        if (isEmpty()) {
            root = new Node(t);
            size++;
            return true;
        }
        Node mid = root;
        Node midPar = null;
        int comp = 0;
        while (mid != null) {
            comp = t.compareTo(mid.value);
            //左边遍历
            if (comp < 0) {
                midPar = mid;
                mid = mid.left;
                //右边遍历
            } else if (comp > 0) {
                midPar = mid;
                mid = mid.right;
            } else {
                //禁止存储重复值
                return false;
            }
        }
        //到这里了,mid代表要添加节点的位置,midPar标识要添加节点的父节点
        //添加在左边
        if (t.compareTo(midPar.value) < 0) {
            midPar.left = new Node(t);
            //添加在右边
        } else {
            midPar.right = new Node(t);
        }
        size++;
        return true;
    }

    /**
     * 递归增加一个结点的方法
     *
     * @param t 增加的结点的值
     * @return true 增加成功
     */
    public boolean addD(T t) {
        if (t == null) throw new IllegalArgumentException("param is null");
        int oldSize = size;
        root = addD(root, t);
        return size > oldSize;
    }

    private Node addD(Node root, T t) {
        if (root == null) {
            size++;
            return new Node(t);
        }
        int comp = t.compareTo(root.value);
        if (comp < 0) {
            root.left = addD(root.left, t);
        } else if (comp > 0) {
            root.right = addD(root.right, t);
        } else {
            throw new RuntimeException("param is exist");
        }
        return root;
    }

    /**
     * 判断一个值的节点是否存在的方法
     *
     * @param t 要判断的值
     * @return true 存在
     */
    public boolean contains(T t) {
        if (t == null) throw new IllegalArgumentException("param is null");
        if (isEmpty()) return false;
        Node mid = root;
        //没找到,没找完就一直找
        while (mid != null) {
            int com = t.compareTo(mid.value);
            //继续左边找
            if (com < 0) {
                mid = mid.left;
                //继续左边找
            } else if (com > 0) {
                mid = mid.right;
                //找到了
            } else {
                return true;
            }
        }
        //找完了,没找到
        return false;
    }

    /**
     * 递归删除一个结点的方法
     *
     * @param t 删除的值
     * @return true 删除成功;
     */
    public boolean removeD(T t) {
        if (t == null) throw new IllegalArgumentException("param is null");
        //树为空
        if (isEmpty()) throw new RuntimeException("Tree is empty");
        int oldSize = size;
        root = removeD(root, t);
        return size < oldSize;
    }

    private Node removeD(Node root, T t) {
        if (root == null) {
            //递归出口,一直找都没找到,知道找到空
            return null;
        }
        int comp = t.compareTo(root.value);
        //左子树递归删除
        if (comp < 0) {
            root.left = removeD(root.left, t);
        } else if (comp > 0) {
            //右子树递归删除
            root.right = removeD(root.right, t);
        } else {
            //双分支,找到右子树最小结点替换再删除
            if (root.left != null && root.right != null) {
                Node min = root.right;
                while (min.left != null) {
                    min = min.left;
                }
                root.value = min.value;
                removeD(root, min.value);
            } else {
                //要删除的节点为单分支或者叶子节点,将要删除的节点的子节点返回给它的父节点
                Node child = root.left != null ? root.left : root.right;
                size--;
                return child;
            }
        }
        return root;
    }

    /**
     * 删除一个节点的方法
     *
     * @param t 要删除的节点值
     * @return true 删除成功
     */
    public boolean remove(T t) {
        if (t == null) throw new IllegalArgumentException("param is null");
        //树为空
        if (isEmpty()) throw new RuntimeException("Tree is empty");
        //树不为空,分三种情况操作
        Node mid = root;
        Node midPar = null;

        while (mid != null) {
            int com = t.compareTo(mid.value);
            if (com < 0) {
                midPar = mid;
                mid = mid.left;
            } else if (com > 0) {
                midPar = mid;
                mid = mid.right;
            } else {
                break;
            }
        }
        //如果mid为null,整个数都找完了,还没有找到要删除的值
        if (mid == null) return false;
        //第一:删除的节点为双分支,先找右子数的最小节点,
        //将要删除的分支节点(只会是单分支或者叶子节点),进行替换再删除
        if (mid.left != null && mid.right != null) {
            Node minPar = mid;
            Node min = mid.right;
            //右子树的最小节点在最左侧的节点
            while (min.left != null) {
                minPar = min;
                min = min.left;
            }
            //找到了右子树的最小节点,进行替换,删除放在后面,此时要删除的节点是右子树的最小节点
            mid.value = min.value;
            midPar = minPar;
            mid = min;
        }
        //删除的节点为叶子节点或者单分支节点
        //第二:要删除的节点是单分支节点
        //获取要删除的分支的子节点
        //如果是单分支,child直接获得对应的节点
        //如果是叶子节点,child就是null
        Node child = mid.left != null ? mid.left : mid.right;
        //如果要删除的是根节点,根节点没有父节点,且根节点为单分支
        if (midPar == null) {
            root = child;
            size--;
            return true;
        }
        //判断要删除的节点是在父节点的位置
        if (midPar.left == mid) {
            midPar.left = child;
            size--;
        } else {
            midPar.right = child;
            size--;
        }
        return true;
    }
    //以上为集合类正常提供的方法
    //---------------------------------------
    //以下为树特有的方法

    /**
     * 栈实现前序遍历的方法(根-左-右)
     *
     * @return 存储遍历后的值的链表
     */
    public List<T> preOrder_Stack() {
        if (isEmpty()) throw new RuntimeException("Tree is empty");
        //存储遍历值的链表
        List<T> list = new ArrayList<>();
        //用于深度遍历的栈
        Stack<Node> stack = new Stack<>();
        //根结点入栈
        stack.push(root);
        //栈不为空,就循环
        while (!stack.isEmpty()) {
            Node pop = stack.pop();//弹栈
            list.add(pop.value);//将弹栈的节点的值存入链表
            if (pop.right != null) stack.push(pop.right);//先将右节点压栈
            if (pop.left != null) stack.push(pop.left);//再将左节点压栈
        }
        return list;
    }

    /**
     * 栈实现中序遍历的方法(左-根-右)
     *
     * @return 存储遍历后的值的链表
     */
    public List<T> inOrder_Stack() {
        if (isEmpty()) throw new RuntimeException("Tree is empty");
        List<T> list = new ArrayList<>();
        Stack<Node> stack = new Stack<>();
        Node mid = root;//标记根节点
        //栈不为空或者标记节点不为空
        while (!stack.isEmpty() || mid != null) {
            //标记根节点有左节点就一直把所有的左节点压栈
            while (mid != null) {
                stack.push(mid);
                mid = mid.left;
            }
            //左节点都压完栈了就弹栈一次
            Node pop = stack.pop();
            //存储弹出结点的值
            list.add(pop.value);
            //将根节点标记为弹出的结点的右节点
            mid = pop.right;
        }
        return list;
    }

    /**
     * 栈实现后续遍历的方法(左-右-根)
     *
     * @return 存储遍历后的值的链表
     */
    public List<T> postOrder_Stack() {
        if (isEmpty()) throw new RuntimeException("Tree is empty");
        List<T> list = new ArrayList<>();
        Stack<Node> stack = new Stack<>();
        stack.push(root);
        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;
    }

    /**
     * 递归前序遍历的方法
     *
     * @return 存储前序遍历值的链表
     */
    public List<T> preOrder() {
        List<T> list = new ArrayList<>();
        preOrder(root, list);
        return list;
    }

    private void preOrder(Node root, List<T> list) {
        if (root == null) return;
        list.add(root.value);
        preOrder(root.left, list);
        preOrder(root.right, list);
    }

    /**
     * 递归中序遍历的方法
     *
     * @return 存储中序遍历值的链表
     */
    public List<T> inOrder() {
        List<T> list = new ArrayList<>();
        inOrder(root, list);
        return list;
    }

    private void inOrder(Node root, List<T> list) {
        if (root == null) return;
        inOrder(root.left, list);
        list.add(root.value);
        inOrder(root.right, list);
    }

    /**
     * 递归后序遍历的方法
     *
     * @return 存储后序遍历值的链表
     */
    public List<T> PostOrder() {
        List<T> list = new ArrayList<>();
        PostOrder(root, list);
        return list;
    }

    private void PostOrder(Node root, List<T> list) {
        if (root == null) return;
        PostOrder(root.left, list);
        PostOrder(root.right, list);
        list.add(root.value);
    }

    /**
     * 利用队列对数进行层级遍历
     *
     * @return 层级遍历值的链表
     */
    public List<T> levelOrder() {
        List<T> list = new ArrayList<>();
        MyListQueen<Node> queen = new MyListQueen<>();//自己实现的线性队列
        queen.offer(root);//根节点入队列
        while (!queen.isEmpty()) {
            //队列不为空就出队列一个
            Node poll = queen.poll();
            list.add(poll.value);
            //从左至右入队列
            if (poll.left != null) queen.offer(poll.left);
            if (poll.right != null) queen.offer(poll.right);
        }
        return list;
    }

    /**
     * 根据二叉搜索树的中序和后序遍历值来新建一个树
     *
     * @param inOrder   中序遍历值:确定根的位置和左右子树的成员
     * @param postOrder 后序遍历:尾值确认根节点
     */
    public void ipBuildBST(List<T> inOrder, List<T> postOrder) {
        root = ipBuildRoot(inOrder, postOrder);
        size = inOrder.size();
    }

    //inOrder  [-8, -4, -2, -1, 3, 5, 6, 7, 15, 20]
    //postOrder[-8, -2, 3, -1, -4, 7, 6, 20, 15, 5]
    private Node ipBuildRoot(List<T> inOrder, List<T> postOrder) {
        //递归出口,切割后的序列如果为空就是没有节点了,如果为1就是一个叶子节点
        if (inOrder.size() == 0) return null;
        if (inOrder.size() == 1) return new Node(postOrder.get(0));
        //后序的最后一个值就是根节点的值
        T nodeValue = postOrder.get(postOrder.size() - 1);
        //根节点所在中序遍历中的下标
        int index = inOrder.indexOf(nodeValue);
        //切割得左子树的中序,切割方法左闭右开
        List<T> leftInOrder = inOrder.subList(0, index);
        //切割得左子树的后序
        List<T> leftPostOrder = postOrder.subList(0, index);
        //切割得右子树的中序
        List<T> rightInOrder = inOrder.subList(index + 1, inOrder.size());
        //切割得右子树的后序
        List<T> rightPostOrder = postOrder.subList(index, postOrder.size() - 1);
        //根据根节点的值创建根节点
        Node node = new Node(nodeValue);
        //递归创建根节点的左子树所有节点
        node.left = ipBuildRoot(leftInOrder, leftPostOrder);
        //递归创建根节点的右子树的所有节点
        node.right = ipBuildRoot(rightInOrder, rightPostOrder);
        //返回根节点
        return node;
    }

    /**
     * 根据二叉树的前序和中序来建树
     *
     * @param preOrder 前序链表
     * @param inOrder  中序链表
     */
    public void piBuildBST(List<T> preOrder, List<T> inOrder) {
        root = piBuildRoot(preOrder, inOrder);
        size = inOrder.size();
    }

    //preOrder  [5, -4, -8, -1, -2, 3, 15, 6, 7, 20]
    //inOrder  [-8, -4, -2, -1, 3, 5, 6, 7, 15, 20]
    private Node piBuildRoot(List<T> preOrder, List<T> inOrder) {
        //递归出口
        if (inOrder.size() == 0) return null;
        if (inOrder.size() == 1) return new Node(preOrder.get(0));
        //获取根节点的值,前序的首元素
        T rootValue = preOrder.get(0);
        //根据中序的得出根节点的位置
        int index = inOrder.indexOf(rootValue);
        //切割得左子树的中序,切割方法左闭右开
        List<T> leftInOrder = inOrder.subList(0, index);
        //切割得左子树的前序
        List<T> leftPreOrder = preOrder.subList(1, index + 1);
        //切割得右子树的中序
        List<T> rightInOrder = inOrder.subList(index + 1, inOrder.size());
        //切割得右子树的前序
        List<T> rightPreOrder = preOrder.subList(index + 1, preOrder.size());
        Node node = new Node(rootValue);
        //递归求子节点
        node.left = piBuildRoot(leftPreOrder, leftInOrder);
        node.right = piBuildRoot(rightPreOrder, rightInOrder);
        return node;
    }

    //节点类
    private class Node {
        private T value;//数据域
        private Node left;//左分支
        private Node right;//右分支

        private Node(T value) {
            this.value = value;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值