二叉搜索树实现与深度优先遍历和广度优先遍历

public class BinarySearchTree<T> {
    private TreeNode root;
    /**
     * 插入数据
     * @param key
     * @param value
     */
    public void insert(int key,T value){
        if(root == null){
            root = new TreeNode(key,value);
        }else{
            insert(root,key,value);
        }

    }

    /**
     * 递归找到插入的节点并插入
     * @param node
     * @param key
     * @param value
     */
    private void insert(TreeNode node,int key,T value){
        //如果值比传进来的节点小就向下执行
        if(key < node.key){
            //如果传进来的节点的左节点没有了,说明是最小的节点了,在最小的节点下添加一个更小的节点
            if(node.leftChild == null){
                TreeNode treeNode = new TreeNode(key,value);
                node.leftChild = treeNode;
            }else{
                //左节点不为空就继续递归
                insert(node.leftChild, key, value);
            }
        }else{
            //同上
            if(node.rightChild == null){
                TreeNode treeNode = new TreeNode(key,value);
                node.rightChild = treeNode;
            }else{
                insert(node.rightChild, key, value);
            }
        }
    }
    /**
     * 获最小的一个节点
     * @param node
     * @return
     */
    private TreeNode min(TreeNode node){
        if(node == null){
            return null;
        }else if(node.leftChild == null){
            return node;
        }
        return min(node.leftChild);
    }
    /**
     * 获取最大的一个节点
     * @param node
     * @return
     */
    private TreeNode max(TreeNode node){
        if(node == null){
            return null;
        }else if(node.rightChild == null){
            return node;
        }
        return max(node.rightChild);
    }
    /**
     * 移除节点
     * @param key
     */
    public void remove(int key){
        remove(root, key);
    }
    /**
     * 移除
     * @param node
     * @param key
     */
    private void remove(TreeNode node,int key){
        if(node == null ){
            return ;
        }
        //如果键比当前的节点的值小就递归查询做节点
        if(key < node.key){
            remove(node.leftChild, key);
        //如果键比当前节点的值大就递归查询右节点
        }else if(key > node.key){
            remove(node.rightChild, key);
        //*找到了要删除的节点,如果左节点和右节点都不为空,就执行替换操作
        }else if(node.leftChild != null && node.rightChild != null){
            //找到右节点中最小的那个节点,因为最小的节点是个单节点,所有很好操作
            TreeNode min = min(node.rightChild);
            //替换搜索到的需要移除的节点为右节点中最小的节点
            node.key = min.key;
            node.data = min.data;
            //然后递归从右节点中删除找到的最小的节点
            remove(node.rightChild,min.key);
        }else{
            //删除单节点或者只有一个孩子节点的情况,如果当前结点的左节点为空就将右节点赋值为当前节点
            node = node.leftChild == null ? node.rightChild:node.leftChild;
        }
    }
    /**
     * 先序遍历,递归
     */
    public void firstOrder(TreeNode node){
        if(node == null){
            return ;
        }
        show(node);
        firstOrder(node.leftChild);
        firstOrder(node.rightChild);
    }
    /**
     * 中序遍历
     * @param node
     */
    public void middleOrder(TreeNode node){
        if(node == null){
            return ;
        }
        middleOrder(node.leftChild);
        show(node);
        middleOrder(node.rightChild);
    }
    /**
     * 后序遍历
     * @param node
     */
    public void lastOrder(TreeNode node){
        if(node == null){
            return ;
        }
        lastOrder(node.leftChild);
        lastOrder(node.rightChild);
        show(node);
    }
    /**
     * 先序遍历,非递归
     * @param node
     */
    public void firstOrderStack(TreeNode node){
        if(node == null){
            throw new RuntimeException("没有节点啊");
        }
        //通过栈来记忆行走的路径
        Stack stack = new Stack<>();
        //将最开的节点压进栈
        stack.push(node);
        //循环获取节点信息,直到节点为空或者栈为空
        while(node != null && !stack.isEmpty()){
            //先访问节点
            show(node);
            //如果当前节点的右节点不为空,就将右节点压进栈
            if(node.rightChild != null){
                stack.push(node.rightChild);
            }
            //如果左节点不为空,就将左节点压进栈
            if(node.leftChild != null){
                stack.push(node.leftChild);
            }
            //出栈,将节点替换为最后进栈的节点,作为基础的节点进行循环
            node = stack.pop();
        }
    }
    /**
     * 先序遍历,非递归2,一路向左
     * @param node
     */
    public void firstOrderStack2(TreeNode node){
        if(node == null){
            throw new RuntimeException("没有节点啊");
        }
        Stack stack = new Stack<>();
        //
        while(node != null || !stack.isEmpty()){
            //先依次访问左节点,并把左节点压进栈
            while(node != null){
                show(node);
                stack.push(node);
                node = node.leftChild;
            }
            //然后转向获得栈顶(最后访问的)的右节点
            node = stack.pop().rightChild;
        }

    }
    /**
     * 中序遍历,非递归
     * @param node
     */
    public void middleOrderStack(TreeNode node){
        if(node == null){
            throw new RuntimeException("没有节点啊");
        }

        Stack stack = new Stack<>();
        //如果节点不为空个或者栈不为空就循环
        while(node != null || !stack.isEmpty()){
            //一路向左,先把所有左节点放入栈中,直到没有左节点了
            while(node != null){
                stack.push(node);
                node = node.leftChild;
            }
            //取得栈顶节点,并访问,然后转向获得他的右节点
            node =stack.pop();
            show(node);
            node = node.rightChild;

        }
    }
    /**
     * 后序遍历,非递归
     * @param node
     */
    public void lastOrderStack(TreeNode node){
        if(node == null){
            throw new RuntimeException("没有节点啊");
        }
        //保存最后访问的节点
        TreeNode last = null;
        Stack stack = new Stack<>();
        while(node != null ){
            //先往最左遍历,直到为空
            while(node != null){
                stack.push(node);
                node = node.leftChild;
            }
            //取出为空前的那一个节点
            node = stack.pop();
            //然后进行循环遍历,第一个是判断是否为叶子节点,如果是叶子节点就直接访问。如果节点的右节点等于最后访问的节点,就代表已经访问过了
            while(node.rightChild == null || node.rightChild == last){
                //访问节点
                show(node);
                //最开始将叶子节点设置为最后的节点,然后第二次判断会递归的将叶子节点上一个节点置为最后的节点
                last = node;
                if(stack.isEmpty()){
                    return;
                }
                //弹出当前节点的上一个节点
                node = stack.pop();
            }
                //放进当前节点,说明当前节点有右节点,记忆当前节点
                stack.push(node);
                //让节点等于当前节点的右节点,转向右节点,因为上面已经通过判断了,到这里就是最左支的节点,然后该节点有右边的节点
                node = node.rightChild;
        }
    }
    /**
     * 广度优先遍历
     * @param node
     */
    public void OrderQueue(TreeNode node){
        Queue queue = new LinkedList<>();
        queue.offer(node);
        //如果队列不为空,就循环遍历
        while(!queue.isEmpty()){
            //出队
            node = queue.poll();
            //访问节点
            show(node);
            //如果当前节点的左节点不为空,就将左节点入队
            if(node.leftChild != null){
                queue.offer(node.leftChild);
            }
            //如果当前节点的右节点不为空,就将右节点入队
            if(node.rightChild != null){
                queue.offer(node.rightChild);
            }
        }
    }
    public void show(TreeNode node){
        System.err.println("key:"+node.key+",vlaue:"+node.data);
    }
    /**
     * 树节点
     * @author yuli
     *
     */
    private  class TreeNode{
        int key;
        T data;
        TreeNode leftChild;
        TreeNode rightChild;
        TreeNode(int key,T data){
            this.key = key;
            this.data = data;
        }
    }
}

你可能感兴趣的:(数据结构,数据结构)