樹遍歷算法概述


首先樹是一種遞歸結構,因此遞歸算法很好寫,關鍵是非遞歸算法。

而非遞歸算法中,樹的四種非遞歸遍歷方式又是核心。下面先介紹樹的四種非遞歸遍歷算法,再介紹其他的非遞歸算法。

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);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM