遞歸與非遞歸轉換的基礎知識是可以正確理解三種樹的遍歷方法:前序,中序和後序,第一篇就是關於這三種遍歷方法的遞歸和 非遞歸算法。 如何用棧實現遞歸與非遞歸的轉換(一)三種遍歷樹的算法 一.爲何要學習遞歸與非遞歸的轉換的實現方法? 1)並非每一門語言都支持遞歸的. 2)有助於理解遞歸的本質. 3)有助於理解棧,樹等數據結構. 二.三種遍歷樹的遞歸和非遞歸算法 遞歸與非遞歸的轉換基於如下的原理:全部的遞歸程序均可以用樹結構表示出來.須要說明的是,這個"原理"並無通過嚴格的 數學證實,只是個人一個猜測,不過在至少在我遇到的例子中是適用的.學習過樹結構的人都知道,有三種方法能夠遍歷樹:前序,中序 ,後序.理解這三種遍歷方式的遞歸和非遞歸的表達方式是可以正確實現轉換的關鍵之處,因此咱們先來談談這個.須要說明的是,這裏 以特殊的二叉樹來講明,不過大多數狀況下二叉樹已經夠用,並且理解了二叉樹的遍歷,其它的樹遍歷方式就不難。 了. 1)前序遍歷 a)遞歸方式: void preorder_recursive(Bitree T) /* 先序遍歷二叉樹的遞歸算法 */ { if (T) { visit(T); /* 訪問當前結點 */ preorder_recursive(T->lchild); /* 訪問左子樹 */ preorder_recursive(T->rchild); /* 訪問右子樹 */ } } b)非遞歸方式 void preorder_nonrecursive(Bitree T) /* 先序遍歷二叉樹的非遞歸算法 */ { initstack(S); push(S,T); /* 根指針進棧 */ while(!stackempty(S)) { while(gettop(S,p)&&p) { /* 向左走到盡頭 */ visit(p); /* 每向前走一步都訪問當前結點 */ push(S,p->lchild); } pop(S,p); if(!stackempty(S)) { /* 向右走一步 */ pop(S,p); push(S,p->rchild); } } } 2)中序遍歷 a)遞歸方式 void inorder_recursive(Bitree T) /* 中序遍歷二叉樹的遞歸算法 */ { if (T) { inorder_recursive(T->lchild); /* 訪問左子樹 */ visit(T); /* 訪問當前結點 */ inorder_recursive(T->rchild); /* 訪問右子樹 */ } } b)非遞歸方式 void inorder_nonrecursive(Bitree T) { initstack(S); /* 初始化棧 */ push(S, T); /* 根指針入棧 */ while (!stackempty(S)) { while (gettop(S, p) && p) /* 向左走到盡頭 */ push(S, p->lchild); pop(S, p); /* 空指針退棧 */ if (!stackempty(S)) { pop(S, p); visit(p); /* 訪問當前結點 */ push(S, p->rchild); /* 向右走一步 */ } } } 3)後序遍歷 a)遞歸方式 void postorder_recursive(Bitree T) /* 中序遍歷二叉樹的遞歸算法 */ { if (T) { postorder_recursive(T->lchild); /* 訪問左子樹 */ postorder_recursive(T->rchild); /* 訪問右子樹 */ visit(T); /* 訪問當前結點 */ } } b)非遞歸方式 typedef struct { BTNode* ptr; enum {0,1,2} mark; } PMType; /* 有mark域的結點指針類型 */ void postorder_nonrecursive(BiTree T) /* 後續遍歷二叉樹的非遞歸算法 */ { PMType a; initstack(S); /* S的元素爲PMType類型 */ push (S,{T,0}); /* 根結點入棧 */ while(!stackempty(S)) { pop(S,a); switch(a.mark) { case 0: push(S,{a.ptr,1}); /* 修改mark域 */ if(a.ptr->lchild) push(S,{a.ptr->lchild,0}); /* 訪問左子樹 */ break; case 1: push(S,{a.ptr,2}); /* 修改mark域 */ if(a.ptr->rchild) push(S,{a.ptr->rchild,0}); /* 訪問右子樹 */ break; case 2: visit(a.ptr); /* 訪問結點 */ } } }