【数据结构随笔】二叉树的前序,中序,后序非递归遍历

三种不同次序的二叉树遍历的递归算法结构相似,只是访问根节点以及遍历左子树、遍历右子树的先后次序不同而已。如果把访问根节点这个不涉及递归的语句抛开,则三个算法走过的路线是一样的。在递归执行的过程中,前序遍历情形是每进入一层 递归调用时先访问根节点,再依次访问它的左,右子树递归调用。中序遍历的情形是从左子树递归调用退出时访问根节点,然后向它的右子树执行递归调用。为把一个递归过程改为非递归过程,一般需要一个工作栈,记录遍历时的回退路径。

1、利用栈的前序遍历非递归算法

算法的基本思想:每访问一个结点前后,在向左子树遍历之前,利用栈记录这个结点的右子女(如果右子女不为空),以便左子树退回时可以直接从栈顶获取到右子树的根节点,继续其右子树的遍历访问。

代码:

 1 void BinaryTree<T>::preOrder(void(*visit)(BinTreeNode<T>*p)){
 2     BinTreeNode<T>* p=root;
 3     stack<BinTreeNode<T>*> S;
 4     while(p!=NULL){
 5         visit(p);
 6         if(p->rightChild) S.push(p->rightChild);
 7         if(p->leftChild)  p=p->leftChild;
 8         else S.pop();
 9     }
10 }

2、利用栈的中序遍历非递归算法

算法的基本思想:在一棵子树中首先访问的是中序下的第一个结点,它位于从根开始的沿leftChild链走到最左下的结点(不一定是叶结点),该节点的leftChild为NULL,访问它的数据后,再遍历该节点的右子树。如果某结点的右子树遍历完或右子树为空,则说明以这个结点为根的二叉树遍历完,此时从栈中退出更上层的结点并访问它,再向它的右子树遍历下去。

代码:

template<typename T>
void BinaryTree<T>::InOrder(void(*visit)(BinTreeNode<T>* p)){
  stack<BinTreeNode<T>*> S;
  BinTreeNode<T>* p=root;  //temp为遍历指针
  do{
    while(p!=NULL){
      S.push(p);
      p=p->leftChild;
    }
    if(!S.empty()){
      p=S.top();
      S.pop();visit(p);
      p=p->rightChild;
    }
  }while(p!=NULL||!S.empty())

3、利用栈的后序非递归算法

算法基本思想:在遍历完左子树时还不能访问根结点,需要再遍历右子树,待右子树遍历完时才访问根结点。所以栈工作中必须记录刚刚访问的是右子树(R)还是左子树(L),待右子树访问完后才访问根结点。所以栈工作中必须注明刚刚左子树还是右子树中。为此可定义栈结点的结构如下所示:

template<typename T>
struct stackNode{
  BinTreeNode<T>* ptr;   //指向树结点的指针
  enum tag {L,R};
  stackNode(BinTreeNode<T>* N=NULL):ptr(N),tag(L){ }
};

在算法中首先使用栈暂存根结点,再向左子树遍历下去,此时根结点tag=L。当访问完左子树中结点并从左子树退回时,还要去遍历根的右子树,此时改变根结点的tag=R。在从右子树中退出时才访问位于栈顶的根结点的值。

代码:

template<typename T>
void BinaryTreeNode<T>::postOrder(void(*visit)(BinTreeNode<T>*p)){
  stack<stackNode<T>> S; stackNode<T> w;
  BinTreeNode<T>* p=root;
  do{
    while(p!=NULL){
      w.ptr=p;w.tag=L;S.push(w);
      p=p->leftChild;
    }
    int continuel=1;  //继续循环的标记,用于遍历完左子树后的右子树遍历;
    while(continuel&&!S.empty()){
      S.pop();p=w.ptr;
      switch(w.tag){
        case L:w.tag=R;S.push(w);
          continuel=0;
          p=p->rightChild;
          break;
        case R:visit(p);break;
      }
    }while(!S.empty())
posted @ 2021-11-01 09:25  天涯海角寻天涯  阅读(212)  评论(0)    收藏  举报