二叉树遍历算法总结(递归与非递归)

一:前言

二叉树的遍历方法分四种:前序,中序,后序以及层次遍历。

其中,前中后遍历方法的实现分递归和非递归,非递归遍历的实现需要借助于栈。

实际上,递归的调用就是一种栈的实现,所以,非递归遍历就需要人工借助栈结构来实现。

而层次遍历需要借助队列。

二:前中后序遍历

递归遍历:

递归遍历的思想和方法很简单,通过调整输出语句来实现前,中,后三种遍历。

代码如下:

1 void show(BiTree T)
2 {
3     if(T)
4     {
5         printf("%c ",T->data);//修改这三个语句的顺序分别实现三种遍历
6         show(T->lchild);
7         show(T->rchild);
8     }
9 }

非递归遍历:

总结了5总不同的非递归遍历算法,四种思路,都需要借助栈来完成。

第一种遍历算法

算法的思路:1.从根结点开始,若当前结点的左孩子不为空,则遍历左孩子并进栈。

         2.结点的左孩子为空时,出栈并遍历当前结点的右孩子结点

           3.以右孩子结点为根结点,又沿着左孩子不断遍历,重复1.2步骤

此算法为前序遍历

  

 1 void preorder1(BiTree T)//前序遍历1
 2 {
 3     LinkStack s;
 4     InitStack(&s);
 5     BiTree temp;
 6     temp = T;
 7     while(temp || !EmptyStack(s)) //第一个条件temp是为了进入循环
 8     {
 9         if(temp)    //一直遍历左子树到底部
10         {
11             Push(&s,temp);
12             printf("%c",temp->data);
13             temp = temp->lchild;
14         }
15         else       //lchild为空,跳转到rchild
16         {
17             Pop(&s,&temp);
18             temp = temp->rchild;
19         }
20     }
21 }

第二种遍历算法

    算法思路与第一种遍历算法一致,只是改变了遍历语句的位置,不是在进栈的时候输出,而是在出栈的时候输出,前序遍历则为中序遍历

    1.从根结点开始,当前结点左孩子不为空时,左孩子进栈。

    2.当前结点左孩子为空时,出栈并输出当前结点,然后跳转该结点的右孩子

    3.重复1,2步骤直到栈空

 1 void inorder(BiTree T)//中序遍历
 2 {
 3     LinkStack s;
 4     InitStack(&s);
 5     BiTree temp = T;
 6     while(temp || !EmptyStack(s))
 7     {
 8         if(temp)
 9         {
10             Push(&s,temp);
11             temp = temp->lchild;
12         }
13         else
14         {
15             Pop(&s,&temp);
16             printf("%c ",temp->data); //出栈时输出则为中序遍历
17             temp = temp->rchild;
18         }
19     }
20 }

第三种遍历算法

    此种算法为前序遍历

    算法思路:1.先将根结点入栈

         2.出栈栈顶并输出,先入栈当前结点的右孩子结点,在入栈当前结点的左孩子结点

                     3.重复第2步直到栈空

 1 void preorder2(BiTree T)
 2 {
 3     LinkStack s;
 4     InitStack(&s);
 5     BiTree temp = T;
 6     Push(&s,temp);
 7     while(!EmptyStack(s))
 8     {
 9         Pop(&s,&temp);            //出栈顶并输出
10         printf("%c ",temp->data);
11         if(temp->rchild)        //入栈右孩子
12         {
13             Push(&s,temp->rchild);
14         }
15         if(temp->lchild)        //入栈左孩子
16         {
17             Push(&s,temp->lchild);
18         }
19     }
20 }

第四种遍历算法:

    后序遍历的非递归实现比较复杂,要保证输出当前结点时左右孩子结点已经输出(或者左右孩子为空)

    即每输出一个结点要满足以下两个条件之一:

    1.此结点的左右孩子为空

    2.此结点的左右孩子已经遍历

    算法思路:1.先将根结点入栈,以栈空为循环停止的条件

         2. 用结点指针pre记录上一个输出结点地址,cur记录当前结点地址

           2.1 当前结点的左右孩子为空时,或者pre记录的结点为当前结点的左(右)孩子时,出栈并输出当前结点,并更新pre

           2.2 否则按照右孩子,左孩子的顺序入栈

         3.循环第2步直到栈空

 1 void postorder(BiTree T)
 2 {
 3     BiTree pre,cur;
 4     LinkStack s;
 5     InitStack(&s);
 6     cur = pre = T;
 7     Push(&s,cur);
 8     while(!EmptyStack(s))
 9     {
10         GetTop(s,&cur);            //当前结点的左右孩子都为空,pre为cur的左孩子或者右孩子时,出栈并输出当前结点
11         if((cur->lchild == NULL && cur->rchild == NULL) || cur->lchild == pre || cur->rchild == pre)
12         {
13             Pop(&s,&cur);
14             printf("%c ",cur->data);
15             pre = cur;            //更新当前结点
16         }
17         else
18         {
19             if(cur->rchild)        //否则入栈右孩子,左孩子
20             {
21                 Push(&s,cur->rchild);
22             }
23             if(cur->lchild)
24             {
25                 Push(&s,cur->lchild);
26             }
27         }
28     }
29 }

第五种遍历算法:

      此种非递归遍历算法思想可以像递归遍历一样通过修改部分的顺序做到:前中后序三种遍历。

      不过便利往往带来的是代码结构上的复杂,此种算法所借助的栈和上面的遍历算法借助的栈不同。

      上面的算法使用的栈存储的数据时一个二叉树结点指针,而此算法栈储存的是一个结构体

      栈数据类型定义:

typedef struct {        // 栈数据定义
        BiTree ptr;
        int task;
}Datatype;

其中,task有两个值,0表示访问,1表示遍历。所有结点的task的初始值为1

      

      算法思路:

      1.根结点先进栈,task初始化为1

      2.出栈,若当前结点的task为0 则访问当前结点,task为1,则修改task为0,并按想要的遍历顺序入栈左右孩子结点。

        例如:若中序遍历,则先入栈右孩子结点,当前结点,左孩子结点。(其他遍历顺序则改一下入栈顺序)

      3.直到栈空,停止循环

     此算法完整代码:

      

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <conio.h>
  4 typedef struct binode{      //二叉树结点定义
  5         char data;
  6         struct binode * lchild,*rchild;
  7 }BiNode,*BiTree;
  8
  9
 10 //非递归遍历所要用到的栈
 11 #define MAX 50
 12 typedef struct {        // 栈数据定义
 13         BiTree ptr;
 14         int task;
 15 }Datatype;
 16
 17
 18 typedef struct {
 19     Datatype * arr;
 20     int top;
 21     int stacksize;
 22 }SqStack;//顺序栈
 23
 24 void InitStack(SqStack *S) //初始化字符栈
 25 {
 26     S->arr = (Datatype*)malloc(sizeof(Datatype)*MAX);
 27     if(S->arr == NULL)
 28     {
 29         printf("初始化失败....\n");
 30         exit(0);
 31     }
 32     S->top = -1;
 33     S->stacksize = MAX;
 34 }
 35
 36
 37 int Push(SqStack *S,Datatype ch)//进栈(字符栈)
 38 {
 39     Datatype *p;
 40     int select;
 41     if(S->top+1 == S->stacksize)    //先判断栈是否已满
 42     {
 43         printf("栈的容量已满,无法进栈");
 44         return 0;
 45     }
 46     S->arr[++S->top] = ch;
 47     return 1;
 48 }
 49
 50 int Pop(SqStack *S,Datatype *ch)//出栈(字符栈)
 51 {
 52     if(S->top < 0)
 53     {
 54         printf("栈为空....\n");
 55         return 0;
 56     }
 57     *ch = S->arr[S->top];
 58     S->top--;
 59     return 1;
 60 }
 61
 62 int GetTopStack(SqStack S,Datatype *ch) //取字符栈顶
 63 {
 64     if(S.top < 0)
 65     {
 66         return 0;
 67     }
 68     *ch = S.arr[S.top];
 69     return 1;
 70 }
 71
 72 int EmptyStack(SqStack S) //判断栈空
 73 {
 74     if(S.top < 0)
 75     {
 76         return 1;
 77     }
 78     return 0;
 79 }
 80
 81 /******************************栈结束*********************************/
 82
 83 void CreateBitree(BiTree *T)  //前序创建二叉树
 84 {
 85   char ch;
 86   scanf(" %c",&ch);
 87   getchar();
 88   if(ch == ‘#‘)
 89   {
 90       *T = NULL;
 91   }
 92   else
 93   {
 94     *T =(BiTree)malloc(sizeof(BiNode));
 95     (*T)->data = ch;
 96     CreateBitree(&((*T)->lchild));
 97     CreateBitree(&((*T)->rchild));
 98   }
 99 }
100
101
102 void View(BiTree T)//非递归遍历  实现不同的遍历顺序修改第一个else语句的结点入栈顺序
103 {
104     Datatype temp;
105     BiTree p;
106     temp.task = 1;
107     temp.ptr = T;
108     SqStack S;
109     InitStack(&S);
110     if(T == NULL) return ;
111     Push(&S,temp);
112     while(!EmptyStack(S))
113     {
114         Pop(&S,&temp);      //先把根出栈
115         p = temp.ptr;           //记录根地址
116         if(temp.task == 0)     //task为0  则访问输出
117         {
118             printf("%c ",temp.ptr->data);
119         }
120         else                        //task为1 则将孩子进栈
121         {
122             if(p->rchild)               //右孩子进栈
123             {
124                 temp.task = 1;
125                 temp.ptr = p->rchild;
126                 Push(&S,temp);
127             }
128             temp.task = 0;          //根的状态由遍历改为访问,然后进栈
129             temp.ptr = p;
130             Push(&S,temp);
131             if(p->lchild)               //左孩子进栈
132             {
133                 temp.ptr = p->lchild;
134                 temp.task = 1;
135                 Push(&S,temp);
136             }
137         }
138     }
139     printf("\n");
140 }
141
142 int main()//二叉树创建:a b d # # e # # c f # # g # #
143 {
144     BiTree T;
145     CreateBitree(&T);
146     printf("中序遍历为:");
147     View(T);
148     return 0;
149 }

三:层次遍历

    层次遍历需要使用队列

    算法思路比较结单,即对每个结点按左孩子,右孩子的顺序进队列即可,出队列时访问即为层次遍历。

    此处就不赘述算法思路步骤了,直接上代码。

    

 1 void DispLayer(BiTree T) //层次遍历
 2 {
 3     LinkQueue rear;                 //装二叉树的结点地址的队列
 4     BiTree view = NULL;
 5     InitQueue(&rear);
 6     if(T == NULL)
 7     {
 8         return ;
 9     }
10     EnQueue(&rear,T);               //先将总树根地址装进去
11     while(!EmptyQueue(rear))    //队列为空则遍历完毕
12     {
13         DeQueue(&rear,&view);           //小树根出队列
14         printf("%c ",view->data);          //输出小树根
15         if(view->lchild)                          //小树根左右孩子存在则入队列
16         {
17             EnQueue(&rear,view->lchild);
18         }
19         if(view->rchild)
20         {
21             EnQueue(&rear,view->rchild);
22         }
23     }
24     printf("\n");
25 }

      以上即为二叉树的各种遍历算法。

时间: 2024-10-27 04:04:24

二叉树遍历算法总结(递归与非递归)的相关文章

二叉树递归与非递归遍历,最近公共父节点算法

#include <iostream> #include <stack> using namespace std; #define MAX 100 //字符串最大长度 typedef struct Node //二叉树结点 { char data; Node *lchild,*rchild; } *Btree; void createBT(Btree &t); //先序构造二叉树 void preorder(Btree &t); //二叉树递归先序遍历 void i

二叉树遍历算法——包含递归前、中、后序和层次,非递归前、中、后序和层次遍历共八种

首先,要感谢网上的参考资料. http://mengliao.blog.51cto.com/876134/1178079(作者:BlackAlpha) http://blog.csdn.net/fzh1900/article/details/14056735(作者:_云淡风轻) http://blog.csdn.net/stpeace/article/details/8138458(作者:stpeace) 二叉树是使用的比较广泛的一种数据结构,这里我写了二叉树的相关操作,包括初始化.新建.以及遍

每天刷个算法题20160518:非递归二叉树遍历

版权所有.所有权利保留. 欢迎转载,转载时请注明出处: http://blog.csdn.net/xiaofei_it/article/details/51502254 为了防止思维僵化,每天刷个算法题.已经刷了几天了,现在贴点代码. 2002年我初中二年级,开始学习BASIC语言.2004年中考之后,开始参加NOIP,系统学习算法.一直非常喜欢算法,但工作后几乎不再碰这些东西.现在准备重新捡起来. 我已经建了一个开源项目,每天的题目都在里面: https://github.com/Xiaofe

重拾算法(1)——优雅地非递归遍历二叉树及其它

重拾算法(1)——优雅地非递归遍历二叉树及其它 本文中非递归遍历二叉树的思想和代码都来自这里(http://jianshu.io/p/49c8cfd07410#).我认为其思想和代码都足够优雅动人了,于是稍作整理,得到如下的程序. 前中后序遍历二叉树 1 public class BinaryTreeNode<T> 2 { 3 public T Value { get;set; } 4 public BinaryTreeNode<T> Parent { get;set; } 5 p

二叉树遍历递归与非递归实现

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 二叉树遍历是二叉树中非常基础的部分,也是学习二叉树必须熟练掌握的部分,下面我们先给出二叉树三种遍历方式的定义,并通过举例来说明二叉树遍历的过程. 二叉树的遍历分为:前序遍历(也叫先序遍历).中序遍历.后序遍历.所谓前.中.后都是根据当前子树根结点相对左右孩子的位置而言,也就是说: 前序遍历:根结点在前,即:根 ----->左------->右: 中序遍历:根结点在中间,即:左------>根------>右: 后序遍历:根结点在最

二叉树详解及二叉树的前序、中序、后序遍历(递归和非递归)

介绍二叉树之前先介绍一下树相关的概念. 树的定义:树是n(n>=0)个有限个数据的元素集合,形状像一颗倒过来的树. 树的概念: 节点:结点包含数据和指向其它节点的指针. 根节点:树第一个结点称为根节点. 结点的度:结点拥有的子节点个数. 叶节点:没有子节点的节点(度为0). 父子节点:一个节点father指向另一个节点child,则child为孩子节点,father为父亲节点 兄弟节点:具有相同父节点的节点互为兄弟节点. 节点的祖先:从根节点开始到该节点所经的所有节点都可以称为该节点的祖先. 子

数据结构二叉树的递归与非递归遍历之 实现可编译(1)java

前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序遍历为例进行说明,中序遍历和后序遍历,以此类推! 二叉树递归与非递归遍历的区别,虽然递归遍历,跟容易读懂,代码量少,运算快,但是却容易出现溢出的问题,所以所以非递归遍历,在处理千万级的运算量时会先的很有用处. 二叉树的先序遍历:先访问根节点,再访问先后访问左右节点.如图: 二叉树的递归遍历之java

JAVA递归、非递归遍历二叉树(转)

原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { private char date; private BinTree lchild; private BinTree rchild; public BinTree(char c) { date = c; } // 先序遍历递归 public static void preOrder(BinTree t) {

Java数据结构系列之——树(4):二叉树的中序遍历的递归与非递归实现

package tree.binarytree; import java.util.Stack; /** * 二叉树的中序遍历:递归与非递归实现 * * @author wl * */ public class BiTreeInOrder { // 中序遍历的递归实现 public static void biTreeInOrderByRecursion(BiTreeNode root) { if (root == null) { return; } biTreeInOrderByRecursi