首先树是一种递归结构,因此递归算法很好写,关键是非递归算法。

而非递归算法中,树的四种非递归遍历方式又是核心。下面先介绍树的四种非递归遍历算法,再介绍其他的非递归算法。

1、层次遍历:

这大概是最简单的了,队列结构,先进根节点,然后循环:出队列头,然后分别进左,右子树节点。如此反复,直至队列为空。

2、先序遍历:

单栈即可。这个在三序遍历中最简单,因为栈只需要保存右子树节点,左子树直接访问。要点:访左存右。一层while循环即可搞定。

3、中序遍历:

单栈即可。这个要比先序难些,因为左右子树节点都要保存在栈中,因此分清父节点是否被访问过极为重要,不然就会无限循环。

怎么区分呢?可以这样区分:以tmp保存父节点,以tmp是否为空作为进栈条件(绝不可以tmp.left是否为空做为进栈条件,这样会分不清父节点是否访问过。不服可以写个试试),进栈后,tmp=tmp.left;出栈后,tmp=tmp.right。这样就可完美区分左右。

由于左节点要一次性进到底,所以总共需要两层while循环。要点:左路进到底,然后退一进右。如此反复。

4、后序遍历:

后序遍历就必须得用符号来标识左右了。实际上中序遍历不用符号已经令我很吃惊,不过中序右子树只保存一层,因此还可以区分左右。但后序左右子树均要保存多层,不用符号就无法区分左右。

实际上后序遍历和中序遍历很像,更实际上,三种遍历的顺序是一样的,先序因为先访问节点,所以不保存左子树,故和后两序差别较大。

因此我们可以仿照中序遍历的写法来写后序。只不过加上符号,标明左右。

会写中序非递归遍历,就会写后序非递归遍历。要点:左路进到底,判断符号,左则变号进右,右则退栈输出。如此反复。

 

另外切记:直接以tmp != null 而不是tmp.left != null 作为左子树递进条件。写循环的要点在于一次把一层写完,而不是一次写残缺多层。

另外:进栈时,我们是知道左右的,出栈时就不知道了。出栈想要防止重复访问,就需要特殊的访问技巧(中序)和特殊的标记符号(后序)。

 

其余还有一些琐碎算法,基本都是树的几种遍历算法的应用:

1、通过前序与中序确定二叉树。前序首节点是根节点,中序,根节点左右为左右子树。据此不断划分,递归构建即可。

2、n个节点二叉树的个数与n个元素的出栈顺序一样,均为卡特兰树。(1/(n+1)) * C(2n,n).

 

 

 

 

java代码如下:

package com.company;

/**
 * Build a binary tree from a generalized list.
 * input is like this:A(B(D,E(G,)),C(,F))#
 */
public class TreeBuilder {

    private static class Node{
        char value;
        Node left;
        Node right;
    }

    /**
     * Build a binary tree from a generalized list.
     * @param glist glist is a generalized list, for example: A(B(D,E(G,)),C(,F))#
     * @return the root node of tree
     */
    public static Node creatTree(String glist){
       if (glist.isEmpty()){
           return null;
       }
       Node[] stack = new Node[glist.length()];
       int pos = 0; int top = -1;
       Node root = new Node();
       if ((glist.charAt(pos) + "").matches("[A-Z]")){ //if is upper character, push in stack
            root.value = glist.charAt(pos);
            stack[++top] = root;
        }else {
           return null;
       }
       while (glist.charAt(pos) != '#'){
           char ch = glist.charAt(pos);
           if (ch == '('){
               pos++;
               if ((glist.charAt(pos) + "").matches("[A-Z]")){
                   Node tmp = new Node();
                   tmp.value = glist.charAt(pos);
                   stack[top].left = tmp;
                   if (glist.charAt(pos+1) == '('){ // if has sub-tree, push in stack
                       stack[++top] = tmp;
                   }
                   pos++;
               }else if (glist.charAt(pos) == ','){
                   stack[top].left = null;
               }
           }else if (glist.charAt(pos) == ','){ // after ',' is right sub-tree.
               pos++;
               if ((glist.charAt(pos) + "").matches("[A-Z]")){
                   Node tmp = new Node();
                   tmp.value = glist.charAt(pos);
                   stack[top--].right = tmp; // pop stack
                   if (glist.charAt(pos+1) == '('){ // if has sub-tree, push in stack
                       stack[++top] = tmp;
                   }
                   pos++;
               }else {
                   stack[top--].right = null;
               }
           }else {
               pos++;
           }
       }
       if (top == -1){ // test whether the result is true.
           System.out.println(true);
       }
       return root;
    }


    /**
     * Build a binary tree from a generalized list.
     * version 2, use switch grammar
     * @param glist glist is a generalized list, for example: A(B(D,E(G,)),C(,F))#
     * @return the root node of tree
     */
    public static Node creatTree2(String glist){
        if (glist.isEmpty()){
            return null;
        }
        Node[] stack = new Node[glist.length()];
        int top = -1;
        int flag = 0; // right sub-tree or left sub-tree
        int pos = 0;  // char position
        Node root = null;
        Node tmp = null;
        while (glist.charAt(pos) != '#'){
            char ch = glist.charAt(pos);
            switch (ch){
                case '(':
                    stack[++top] = tmp;// push in
                    pos++;
                    flag = 1;  // left sub-tree
                    break;
                case ',':
                    pos++;
                    flag = 2; // right sub-tree
                    break;
                case ')':
                    pos++;
                    top--;  // pop out
                    break;
                default:
                    tmp = new Node();
                    tmp.value = ch;
                    if (root == null){  // link the root
                        root = tmp;
                    }
                    if (flag == 1){
                        stack[top].left = tmp;
                    }else if (flag == 2){
                        stack[top].right = tmp;
                    }
                    pos++;
            }
        }
        return root;
    }

    public static void printPreTree(Node root){
        if (root != null){
            System.out.print(root.value + " ");
            printPreTree(root.left);
            printPreTree(root.right);
        }
    }

    /**
     * the non-recursion pre traversal of tree
     * @param root
     */
    public static void printPreTreeNonRecursion(Node root){
        Node tmp = root;
        Node[] stack = new Node[20];
        int top = -1;
        while (tmp != null || top != -1){
            if (tmp != null){
                System.out.printf(tmp.value + " ");
                if (tmp.right != null){
                    stack[++top] = tmp.right;
                }
                tmp = tmp.left;
            }else {
                tmp = stack[top--];
            }
        }
        System.out.println();
    }

    /**
     * the hierarchical traversal of tree
     * @param root
     */
    public static void printHierarchical(Node root){
        Node[] queen = new Node[20];
        int head = 0;
        int tail = 0;
        Node tmp = root;
        queen[tail++%20] = tmp;
        while (tail != head){
            tmp = queen[head++%20];
            System.out.printf(tmp.value + " ");
            if (tmp.left != null){
                queen[tail++%20] = tmp.left;
            }
            if(tmp.right != null){
                queen[tail++%20] = tmp.right;
            }
        }
        System.out.println();
    }

    /**
     * 树的中序非递归遍历
     * the middle non-recursion traversal of tree
     * @param root
     */
    public static void printMidTreeNonRecursion(Node root){
        Node[] stack = new Node[20];
        int top = -1;
        Node tmp = root;
        while (tmp != null || top != -1){
            while (tmp != null){
                stack[++top] = tmp;
                tmp = tmp.left;
            }
            if (top != -1){
                tmp = stack[top--];
                System.out.printf(tmp.value + " ");
                tmp = tmp.right;
            }
        }
        System.out.println();
    }

    /**
     * 树的中序递归遍历
     * the middle recursion traversal of tree
     * @param root
     */
    public static void printMidTree(Node root){
        if (root != null){
            printMidTree(root.left);
            System.out.printf(root.value + " ");
            printMidTree(root.right);
        }
    }

    /**
     * 树的后序递归遍历
     * the suffix recursion of traversal of tree
     */
    public static void printSufTree(Node root){
        if (root != null){
            printSufTree(root.left);
            printSufTree(root.right);
            System.out.printf(root.value + " ");
        }
    }

    /**
     * the suffix non-recursion traversal of tree
     */
    public static void printSufTreeNonRecursion(Node root){
        class FlagNode{
            Node node;
            int flag;
        }
        FlagNode[] stack = new FlagNode[20];
        int top = -1;
        Node tmp = root;
        while (top != -1 || tmp != null){
            while (tmp != null){
                FlagNode flagNode = new FlagNode();
                flagNode.node = tmp;
                flagNode.flag = 0;
                stack[++top] = flagNode;
                tmp = tmp.left;
            }
            if (top != -1){
                if (stack[top].flag == 0){
                    stack[top].flag = 1;
                    tmp = stack[top].node.right;
                }else {
                    System.out.printf(stack[top--].node.value + " ");
                }
            }
        }
        System.out.println();
    }
    /**
     * 以广义表的形式把树打印出来
     * @param root
     */
    public static void printGTree(Node root){
        if(root != null){
            System.out.printf(root.value + "");
            if (root.left != null || root.right != null) {
                System.out.printf("(");
                printGTree(root.left);
                System.out.printf(",");
                printGTree(root.right);
                System.out.printf(")");
            }
        }
    }

    public static void main(String[] args) {
    // write your code here
        Node root =creatTree("A(B(G,H(K,L)),C(D,E(F,)))#");
        System.out.println("Pre traversal: ");
        printPreTree(root);
        System.out.println();
        printPreTreeNonRecursion(root);

        System.out.println(" : ");
        printHierarchical(root);



        Node root2 =creatTree2("A(B(G(H(K(,J(,Z)),),I),M(,N)),C(D,E(F,)))#");
        System.out.println("Mid traversal: ");
        printMidTree(root2);
        System.out.println();
        printMidTreeNonRecursion(root2);
        System.out.println("Suf traversal: ");
        printSufTree(root2);
        System.out.println();
        printSufTreeNonRecursion(root2);
    }
}