二叉树的递归遍历与非递归算法实现

转载 2013年12月05日 14:14:54
     通过递归算法与非递归算法的比较,更好地理解各自的特点。非递归其实就是调用栈的基本操作,进栈,出栈等。
这里面也正好复习了下栈的基本算法的实现。
 
栈和队列的实现在我的前一篇博文里。
 
基本数据结构
typedef struct BiNode
{
      char data;   //此处,二叉树中节点值类型为字符型
      struct BiNode *lchild,*rchild;     //左右孩子节点
}BiNode,*BiTree;   
 
二叉树的创建
先申请根节点的空间,然后赋值,然后分别递归建立其左子树和右子树
//按照先序序列输入构建一棵二叉树
View Code

 

二叉树的递归遍历算法

//二叉树的遍历,三种顺序的递归遍历,其实就是访问根节点的顺序不同,这里的访问操作是打印结点,也可以是对结点其他的操作
 
View Code

 

 
二叉树的非递归遍历算法
 
二叉树先序遍历的非递归算法
复制代码
/* 设置一个存放结点指针的栈 S ,从根结点开始,每访问一结点后,按先序规则走左子树,若右子树存在,

则将右子树指针进栈,以便以后能正确地返回到该右子树上进行遍历访问。

*/

void PreTraverse(BiTree T)

{

     BiNode *p;

     Stack S;

     S=InitStack();

      if (T)

     {

           Push(S,T);  // 根结点指针进栈

            while (!StackEmpty(S))

           {

                p=Pop(S);  // 出栈,栈顶元素赋给 p

                 while (p)

                {

                     printf( "%c\t" ,p->data);  // 访问 p结点

                      if (p->rchild)

                           Push(S,p->rchild);  // 右子树存在时,进栈

                     p=p->lchild;            // 继续沿着左子树往下走

                }

           }

     }

}
复制代码

/*

说明:内部循环是从 p 结点出发一直走到最左,走的过程中保存了每一个右子树的地址,
(因为右子树还没有被访问)而且是先进后出的,即先保存的比后保存的更先被用作返回地址,
所以是用栈。外循环正好是当内部循环不下去的时候,退一栈的情形。即换成他的右子树。
*/
 
// 二叉树的中序遍历的非递归算法
复制代码
/*

同前序遍历 , 栈S 存放结点指针。对每棵子树 ( 开始是整棵二叉树 ),沿左找到该子树在中序下的第一结点

( 但寻找路径上的每个结点指针要进栈 ), 访问之; 然后遍历该结点的右子树 ,

又寻找该子树在中序下的第一结点, .. …直到栈S 空为止。

*/


void InTraverse(BiTree T)

{

     BiNode *p;

     Stack S;

     S=InitStack();

     Push(S,T);  // 根结点指针进栈

      while (!StackEmpty(S))

     {

            while ((p=GetsTop(S))&&p)  //取栈顶元素且存在,赋给 p

                Push(S,p->lchild);    //p 的左子树进栈

           p=Pop(S);               // 去掉最后的空指针

            if (!StackEmpty(S))

           {

                p=Pop(S);       // 弹出栈顶元素,赋给 p

                printf( "%c\t" ,p->data);   // 访问 p结点

                Push(S,p->rchild);     // 右子树进栈,然后遍历右子树

           }

     }

}
复制代码

 /*

说明:和前序不一样,这里的栈保存的是根结点的地址(因为中序遍历先访问左子树,
而根结点没有被访问到。而前序遍历不一样,他一开始就访问根结点,
所以他不保存根结点的地址而是保存右子树的地址,因为右子树还没有被访问。
总之,用栈就是为了帮我们保存还没有被访问的地址,以便将来我们能找到返回的地址)。
*/
 
/* 后序遍历二叉树的非递归算法 */
复制代码
/* 对一个结点是否能访问,要看他的左、右子树是否遍历完, */

/* 所以每一个结点对应一个标志位 -tag 。tag=0 ,表示该结点暂不能访问; tag=1 ,表示该结点可以访问 */

/* 其实是区分这次返回是遍历完左子树返回的还是遍历完右子树返回的,如果是左子树返回的那么就不能访问根结点, */

/* 如果是右子树返回的就能访问根结点。当搜索到某 P 结点时,先要遍历其左子树,因而将结点地址 P 及tag=0 进栈; */

/* 当P 结点的左子树遍历完之后,再遍历其右子树,又将地址 P 及tag=1 进栈;当 P结点右子树遍历完之后( tag=1 ),便可对 P结点进行访问 */

void PostTraverse(BiTree T)

{

      int tag;

     BiNode *p;

     Stacks S;

     SNode sdata;

     S=InitStacks();

     p=T;

      while (p||!StacksEmpty(S))

     {

            while (p)

           {

                sdata.q=p;

                sdata.tag=0;

                Pushs(S,&sdata);   //(p,0) 进栈

                p=p->lchild;      // 遍历p 之左子树

           }

           sdata=*Pops(S);  // 退栈

           p=sdata.q;     // 取指针

           tag=sdata.tag; // 状态位

            if (tag==0)     //从左子树返回时,根的 tag=0

           {

                sdata.q=p;

                sdata.tag=1;      // 这时要进入根的右子树了,所以根的 tag=1 ,下次碰到根时就可以访问了

                Pushs(S,&sdata);   //(p,1) 进栈,根还得进一次栈

                p=p->rchild;     // 遍历右子树

           }

            else           //tag=1,这是说明了右子树访问完了返回,所以这次要对根进行访问了

           {

                printf( "%c\t" ,p->data);

                p=NULL;

           }

     }

}
复制代码

 

二叉树的层次遍历
复制代码
// 二叉树的层次遍历

void LevelTraverse(BiTree T)

{

     BiNode *p;

     LinkQueue *Q;

     InitQueue(Q);

     EnQueue(Q,T);

      while (!QueueEmpty(Q))

     {

           p=DeQueue(Q);

           printf( "%c\t" ,p->data);

            if (p->lchild!=NULL)

                EnQueue(Q,p->lchild);

            if (p->rchild!=NULL)

                EnQueue(Q,p->rchild);

     }

}
复制代码

 

下面是完整代码:
View Code

 

/*测试数据*/
/* 分别是构建二叉树的输入数据以及先序、中序、后序、层次遍历序列:
ABE##C#D##F#GH#I##J##
ABECDFGHIJ
EBCDAFHIGJ
EDCBIGJGFA
ABFECGDHJI
 */
图画得有点丑,见笑了。

二叉树的递归遍历与非递归算法实现

通过递归算法与非递归算法的比较,更好地理解各自的特点。非递归其实就是调用栈的基本操作,进栈,出栈等。 这里面也正好复习了下栈的基本算法的实现。   栈和队列的实现在我的前一篇博文里。   ...

C++ 实现求二叉树的深度及遍历(递归与非递归算法)

#include #include #include using namespace std; struct BSTNode { int data; BSTNode * LChild,* ...

二叉树前序、中序、后序遍历的递归与非递归算法实现

//前序 递归 void preOrderRecursive(Tree * t) { if( !t ) return; visist(t); ...
  • kobep
  • kobep
  • 2013年04月24日 10:50
  • 411

【数据结构】二叉树(前、中、后)序遍历的递归与非递归算法

对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对 于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在...

二叉树中序遍历和后序遍历的递归与非递归算法

昨天写的前序遍历的递归与非递归算法,在非递归算法中主要还是借用到了栈这一工具,其实在中序遍历和后序遍历中依旧可以理由栈的特性来进行非递归的遍历 操作。 1.中序遍历 1.1 中序遍历的递归算法 二...

二叉树遍历的递归与非递归算法

二叉树遍历主要有四种:前序遍历,中序遍历,后序遍历,层序遍历。
  • Veahlin
  • Veahlin
  • 2017年02月25日 16:33
  • 181

C语言 二叉树的遍历 递归和(多种)非递归算法

//二叉树遍历 //作者:nuaazdh //时间:2011年12月1日 #include #include #define OK 1 #define ERROR...
  • nuaazdh
  • nuaazdh
  • 2012年05月31日 20:18
  • 17479

二叉树的遍历(前 中 后序 )递归 非递归算法

机会是留个有准 备的人的,如果你没有得到机会,那只能说明你准备不足。      又一次的机会失掉了,好像已经错过了太多的机会,后悔也是没用的,好好总结,继续往前走吧。     这个二叉树,总是感觉...
  • Zoelov
  • Zoelov
  • 2012年10月31日 17:13
  • 832

二叉树层序遍历的递归和非递归算法

二叉树层序遍历的递归和非递归算法

剑指offer面试题19二叉树的镜像和二叉树的前中后遍历递归和非递归算法

#include #include #include #include #include using namespace std; struct BinaryTreeNode { int d...
  • twlkyao
  • twlkyao
  • 2013年06月25日 09:57
  • 768
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:二叉树的递归遍历与非递归算法实现
举报原因:
原因补充:

(最多只允许输入30个字)