数据结构-二叉树(3)二叉树遍历的非递归算法

不使用递归算法,想遍历二叉树:

#include <istream>
#include "stack.h"
#include "queue.h"
using namespace std;

void BinaryTree<T>::PreOrder(void (*visit)(BinTreeNode<T> *p)){
//  每次访问一个结点之后,用栈记录该结点的右子女,以便从左子女退回时可以直接从栈顶取得右子女的根结点,继续右子女的前序遍历
    stack<BinTreeNode<T>*> S;
    BinTreeNode<T> *p=root;
    S.Push(NULL);
    while(p!=NULL){
        visit(p);
        if(p->rightChild!=NULL) S.Push(p->rightChild);
        if(p->leftChild!=NULL) p=p->leftChild;
        else S.Pop(p);  //左子树为空
    }
}

template <class T>
void BinaryTree<T>::PreOrder(void (*visit)(BinTreeNode<T> *p)){
//  另一种前序遍历的方法。进栈时先进右子树结点地址,再进左子树;出栈时相反。
    stack<BinTreeNode<T>*> S;
    BinTreeNode<T> *p;
    S.Push(root);
    while (!S.IsEmpty()) {
        S.Pop(p);visit(p);
        if(p->rightChild!=NULL) S.Push(p->rightChild);
        if(p->leftChild!=NULL) S.Push(p->leftChild);
    }
}

template <class T>
void BinTreeNode<T>::LevelOrder(void (*visit)(BinTreeNode<T> *p)){
//  利用队列进行层次性遍历
    Queue<BinTreeNode<T>*> Q;
    BinTreeNode<T> *p=root;
    Q.EnQueue(p);
    while(!Q.IsEmpty()){
        Q.DeQueue(p);visit(p);
        if(p->leftChild!=NULL) Q.EnQueue(p->leftChild);
        if(p->rightChild!=NULL) Q.EnQueue(p->rightChild);
    }
}

template <class T>
void BinaryTree<T>::InOrder(void (*visit)(BinTreeNode<T> *p)){
// 利用栈进行中序遍历
    stack<BinTreeNode<T>*> S;
    BinTreeNode<T> *p=root;
    do{
        while(p!=NULL){
            S.Push(p);
            p=p->leftChild;
        }
        if(!S.IsEmpty()){
            S.Pop(p);visit(p);
            p=p->rightChild;
        }
    }while(p!=NULL || !S.IsEmpty());  //栈为空同时遍历指针也为空时结束循环
}

template <class T>
struct stkNode{
//  后序遍历时,必须借助栈结点结构,记录刚才是在左子树中还是右子树中
    BinTreeNode<T> *ptr;
    enum tag{L,R};
    stkNode(BinTreeNode<T> *N=NULL):ptr(N),tag(L){}
}

template <class T>
void BinaryTree<T>::PostOrder(void (*visit)(BinTreeNode<T> *p)){
    Stack<stkNode<T>> S;
    stkNode<T> w;
    BinTreeNode<T> *p=root;
    do{
        while(p!=NULL){
            w.ptr=p;w.tag=L;S.Push(w);
            p=p->leftChild;
        }
        int continue1=1;    //继续循环标记,用于Case L情况结束小循环继续大循环。Case R情况继续小循环。
        while(continue1 && !S.IsEmpty()){
            S.Pop(w);p=w.ptr;
            switch(w.tag){
                case L:w.tag=R;S.Push(w);
                       continue1=0;
                       p=p->rightChild;
                       break;
                case R:visit(p);
                       break;
            }
        }
    }while(!S.IsEmpty());
    cout<<endl;
}

 

posted @ 2018-08-08 16:41  扬羽流风  阅读(264)  评论(0编辑  收藏  举报