首先樹是一種遞歸結構,因此遞歸算法很好寫,關鍵是非遞歸算法。
而非遞歸算法中,樹的四種非遞歸遍歷方式又是核心。下面先介紹樹的四種非遞歸遍歷算法,再介紹其他的非遞歸算法。
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); } }