1. 程式人生 > >記錄一下關於二叉樹的非遞歸遍歷

記錄一下關於二叉樹的非遞歸遍歷

printf order type typedef print 課本 pos else if post

利用棧的非遞歸先序遍歷二叉樹:

額,這個是我自己寫的,可能算法有點啰嗦……

/**********
【題目】試利用棧及其基本操作寫出二叉樹T的非遞歸
的先序遍歷算法。
二叉鏈表類型定義:
typedef struct BiTNode {
  TElemType  data;
  struct BiTNode  *lchild,*rchild;
} BiTNode, *BiTree;
可用棧類型Stack的相關定義:
typedef BiTree SElemType;   // 棧的元素類型
Status InitStack(Stack &S); 
Status StackEmpty(Stack S); 
Status Push(Stack &S, SElemType e);
Status Pop(Stack &S, SElemType &e); 
Status GetTop(Stack S, SElemType &e); 
*********
*/ /*思路:先訪問根節點,然後向左一直走下去,每走一個都是先訪問根節點,並沿途把右子樹入棧。向左走完後,開始搞棧裏面的元素, 對棧裏面的元素,先看它的右子樹存不存在,若存在則入棧,然後再對這個元素的右子樹也進行向左走操作*/ void traverseLeft(BiTree T, Stack &S, void (*visit)(TElemType)); Stack S; void PreOrder(BiTree T, void (*visit)(TElemType)) /* 使用棧,非遞歸先序遍歷二叉樹T, */ /* 對每個結點的元素域data調用函數visit */ { InitStack(S); BiTree tree2
= T; BiTree treeTemp = tree2; while(treeTemp && treeTemp->data!=#) { //好吧做了後面的題後發現好像可以不用這個data=‘#‘,但懶得改了 visit(treeTemp->data); printf("visit the root:%c\n",treeTemp->data); traverseLeft(treeTemp->lchild, S, visit);//遍歷左邊的節點,並沿途將他們的右子樹入棧,遍歷後treeTemp指向最左邊那個子樹
while(!StackEmpty(S)) { printf("get into the stack\n"); Pop(S, treeTemp); visit(treeTemp->data); printf("visit the stack of the rchild:%c\n",treeTemp->data); if(treeTemp->rchild && treeTemp->rchild->data!=#) { Push(S, treeTemp->rchild); } traverseLeft(treeTemp->lchild, S, visit); } treeTemp = tree2->rchild; tree2 = tree2->rchild; } } void traverseLeft(BiTree T, Stack &S, void (*visit)(TElemType)) { while(T && T->data!=#) { visit(T->data); printf("visit the lchild:%c\n",T->data); if(T->rchild && T->data!=#) { Push(S, T->rchild); if(!StackEmpty(S)) { printf("push %c into the stack\n",T->rchild->data); } } T = T->lchild; } }

利用棧實現非遞歸後序遍歷二叉樹:

這個是網上找的實現算法:

/**********
【題目】試利用棧及其基本操作寫出二叉樹T的非遞歸
的後序遍歷算法(提示:為分辨後序遍歷時兩次進棧的
不同返回點,需在指針進棧時同時將一個標誌進棧)。
二叉鏈表類型定義:
typedef struct BiTNode {
  TElemType  data;
  struct BiTNode  *lchild,*rchild;
} BiTNode, *BiTree;
可用棧類型Stack的相關定義:
typedef struct {
  struct BiTNode *ptr; // 二叉樹結點的指針類型
  int      tag; // 0..1
} SElemType;    // 棧的元素類型
Status InitStack(Stack &S); 
Status StackEmpty(Stack S); 
Status Push(Stack &S, SElemType e);
Status Pop(Stack &S, SElemType &e); 
Status GetTop(Stack S, SElemType &e); 
**********/



void PostOrder(BiTree T, void (*visit)(TElemType))
/* 使用棧,非遞歸後序遍歷二叉樹T,     */
/* 對每個結點的元素域data調用函數visit */
{
    SElemType a,b; //a可以說是主要遍歷這個樹的一個指針這樣的,b是主要用來處理從棧出來的東西

Stack s; 

a.ptr=T; 

while(a.ptr){ 

    if(a.ptr->lchild&&a.ptr->rchild){ //如果有兩個孩子的話

        a.tag=1; 

        Push(s,a); //屬於1號

        a.ptr=a.ptr->lchild; //走左孩子 

    } 

    else if(a.ptr->lchild&&!a.ptr->rchild){ //如果只有左孩子的話

        a.tag=0; //屬於0號

        Push(s,a); 

        a.ptr=a.ptr->lchild; //走左孩子

    } 

    else if(!a.ptr->lchild&&a.ptr->rchild){ //如果只有右孩子的話

        a.tag=0; //屬於0號

        Push(s,a); 

        a.ptr=a.ptr->rchild; //走右孩子

    } 

    else if(!a.ptr->lchild&&!a.ptr->rchild) { //如果是葉子結點的話

        (*visit)(a.ptr->data); //先訪問這個葉子結點

        Pop(s,b); //然後就開始訪問棧裏面的東西了,出棧,用b來裝

        if(b.tag==1) //如果棧裏面遲來的是個有兩個孩子的東西,說明剛剛它走的是左孩子,然後現在要走它的右孩子並把它變成tag為0

        { 

            b.tag=0; 

            a.ptr=b.ptr->rchild; //走右孩子

            Push(s,b); 

        } 

        else if(b.tag==0) //如果從棧出來的這個是只有一個孩子的,說明它的孩子已經訪問過了,因為棧裏的已經是往回走了嘛,它進去的時候如果只有一個孩子,那
                            //回去就說明它的孩子都被訪問過了

        { 

            a=b; //依然用a來走遍歷

            while(a.tag==0&&!StackEmpty(s)) //如果棧未空且出來的元素都是tag為0的
    
            { 
    
                (*visit)(a.ptr->data); 

                Pop(s,a); 

            } 

            if(a.tag==0&&StackEmpty(s)){ //如果棧裏面已經沒有元素了,就指向NULL,也就是遍歷結束

                (*visit)(a.ptr->data); 

                a.ptr=NULL; 

            } 

            else if(a.tag==1){ 

                b=a; 

                a.ptr=b.ptr->rchild; 

                b.tag=0; 

                Push(s,b); 

            } 

        } 

    }     

} 

}






//網上的答案:寫在函數體裏面就行了
/*
SElemType a,b; 

Stack s; 

a.ptr=T; 

while(a.ptr){ 

    if(a.ptr->lchild&&a.ptr->rchild){ //如果有兩個孩子的話

        a.tag=1; 

        Push(s,a); //屬於1號

        a.ptr=a.ptr->lchild; //走左孩子 

    } 

    else if(a.ptr->lchild&&!a.ptr->rchild){ //如果只有左孩子的話

        a.tag=0; //屬於0號

        Push(s,a); 

        a.ptr=a.ptr->lchild; //走左孩子

    } 

    else if(!a.ptr->lchild&&a.ptr->rchild){ //如果只有右孩子的話

        a.tag=0; //屬於0號

        Push(s,a); 

        a.ptr=a.ptr->rchild; //走右孩子

    } 

    else if(!a.ptr->lchild&&!a.ptr->rchild) { //如果是葉子結點的話

        (*visit)(a.ptr->data); //先訪問這個葉子結點

        Pop(s,b); //出棧,用b來裝

        if(b.tag==1) //有兩個孩子的話

        { 

            b.tag=0; 

            a.ptr=b.ptr->rchild; 

            Push(s,b); 

        } 

        else if(b.tag==0) 

        { 

            a=b; 

            while(a.tag==0&&!StackEmpty(s)) 
    
            { 
    
                (*visit)(a.ptr->data); 

                Pop(s,a); 

            } 

            if(a.tag==0&&StackEmpty(s)){ 

                (*visit)(a.ptr->data); 

                a.ptr=NULL; 

            } 

            else if(a.tag==1){ 

                b=a; 

                a.ptr=b.ptr->rchild; 

                b.tag=0; 

                Push(s,b); 

            } 

        } 

    }     

} 

 

利用棧的非遞歸終須遍歷二叉樹在數據結構課本的p135上

記錄一下關於二叉樹的非遞歸遍歷