After you create a binary tree, recursive / non-recursive preorder / inorder / traversing Binary Tree Algorithm

package BinaryTree;



import java.util.Scanner;
import java.util.Stack;

//二叉树的节点
public class Node {
    String value;
    Node left;
    Node right;
    public Node(String value){
        this.value = value;
    }


    /**
     * 创建一个二叉树
     * 规定:不允许输入空数据,即输入的二叉树得至少有一个节点
     * para:data是一个字符串数组,存储二叉树先序遍历得到的节点值,
     * start是节点值在数组中开始下标,end是节点值在数组中的结束下标,如果数组中没有值,start = -1, end = -1
     * 在进行判断时,不能使用data.length进行判断,因为递归函数使用的是同一个字符串数组作为输入变量,只是start和end的值不一样
     * 输入的形式是作为一个满二叉树进行输入,空节点用$号代替
     * 采用先序的方式创建一个二叉树
     */
    public static Node createBinaryTree(String[] data,int start,int end){//由于使用递归算法,所有得多设置几个参数
        if((end == start)){//只有一个节点的情况下,这就是递归结束条件,不可能出现end小于start的情况
            if(data[start].equals("$")){
                return null;
            }else{
                return new Node(data[start]);
            }
        }else{
            if(data[start].equals("$")){//如果说某个子树的根节点为$,直接返回null,下面也不用计算了1,
                return null;
            }
            Node root = new Node(data[start]);
            int halfLength = (end - start)/2;
            Node leftChild = createBinaryTree(data,start+1,start+halfLength);
            Node rightChild = createBinaryTree(data,start+halfLength+1,start+2*halfLength);
            root.left = leftChild;
            root.right = rightChild;
            return root;
        }
    }

    /**
     * 先序递归输出二叉树
     */
    public static void preOrder(Node root){
        if(root != null){
            System.out.print(root.value+" ");
            preOrder(root.left);
            preOrder(root.right);
        }
    }

    /**
     * 中序递归输出二叉树
     */
    public static void inOrder(Node root){
        if(root != null){
            inOrder(root.left);
            System.out.print(root.value+" ");
            inOrder(root.right);
        }
    }

    /**
     * 后序递归遍历二叉树
     */
    public static void postOrder(Node root){
        if(root != null){
            postOrder(root.left);
            postOrder(root.right);
            System.out.print(root.value+" ");
        }
    }

    /**
     * 后序非递归遍历二叉树
     * 后序非递归得使用到栈的结构
     * 两层循环
     * 我们要记得的是非递归遍历的栈中保存的是一个路径上的节点
     * 出栈时访问,在栈中就没有访问
     * 如果是回退到一个节点,那么只有可能该节点右子树和该节点没有被访问,该节点的左子树肯定被访问了
     * 总结一下:外循环栈不为空,内循环一个左分支持续入栈,右分支持续出栈,出栈判断栈是否为空
     */
    public static void postOrderNotRecursive(Node root){
        Stack<Node> stack = new Stack<>();//<>是泛型机制
        if(root == null){
            return;
        }
        Node node = root;
        stack.push(node);
        node = node.left;
        //两层循环、最外层循环就是栈不为空,因为根节点是第一个进栈,最后一个出栈的,但是得先进栈根节点
        while(!stack.isEmpty()){
            while(node != null){
                stack.push(node);
                node = node.left;
            }
            //到这儿是左遍历结束,现在的目的是访问栈顶节点的右子树,先把这个节点拿出来,不能pull出来
            //当这个时候,弹出栈中的右分支,直到遇到左节点,这里稍微难写一点,注意,右分支不是右子树为空的节点,而是栈上节点是栈下节点的右子节点
            //上一次弹出的节点如果是栈顶节点的右节点,则弹出栈顶节点
            Node rightNode = null;
            node = stack.peek();
            while(node.right == rightNode){
                rightNode = stack.pop();
                System.out.print(rightNode.value+" ");
                if(!stack.isEmpty()) {
                    node = stack.peek();
                }else{
                    return;
                }
            }

            node = node.right;
        }

    }

    /**
     * 先序遍历非递归形式
     * 也要使用栈
     */
    //仍然使用栈结构
    //循环条件是什么呢?
    //因为栈中元素是没访问过的,而根节点是第一个访问的。
    //之前想过,只有后序遍历栈中的元素有规律,而先序和中序都没有什么规律。
    //其实先序遍历的非递归形式很简单,我们要记住:一个节点访问过了就一定出栈了,如果在栈中,就一定是没有访问过的。
    //那么就很简单了,根节点,压入,弹出,但是弹出之前得先把它的左右节点压入栈中,不然的话,左右子树的信息会全部丢失,那么又有问题来了
    //先压入哪个节点呢?因为栈是先进后出,也就是先压入的后访问,那么我们自然得先把右节点压进去了,如果有子节点不为空,那就不用压入了,
    //因为节点的访问是从栈中取出再访问,节点的压入,也是把一个节点弹出,然后拿它的左右子节点压入,那如果栈中没元素了,就没元素访问,也没元素压入了
    //所有循环条件也是栈不为空
    public static void preOrderNotRecursive(Node root){
        if(root == null){
            return;
        }
        Stack<Node> stack = new Stack<>();
        Node node = root;
        stack.push(node);
        while(!stack.isEmpty()) {
            node = stack.pop();
            System.out.print(node.value+" ");
            if (node.right != null) {//先压入右节点,再压入左节点
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
    }

    /**
     * 中序遍历的非递归形式
     * 中序的外层循环结束条件变了,不是栈不为空了,而是弹出节点的右节点不为空,
     */
    public static void inOrderNotRecursive(Node root){
        if(root == null){
            return;
        }
        Stack<Node> stack = new Stack<>();
        Node node = root;
        while(node !=null) {
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
            do {
                node = stack.pop();
                System.out.print(node.value + " ");
                node = node.right;
            } while(!stack.isEmpty()&&node == null);//和非递归后续遍历一样,在进行持续出栈的时候一定要判断栈不为空。
        }
    }




    /**
     * 测试函数
     */
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        String[] data = s.split(",");

        Node root = createBinaryTree(data,0,data.length-1);
        inOrderNotRecursive(root);
    }
}






The time complexity of the algorithm is O (N), the spatial complexity is O (h), h is the height of the tree.

Guess you like

Origin blog.csdn.net/shen19960603/article/details/90743652