二叉树的遍历

来源:互联网 发布:c语言大于号怎么打 编辑:程序博客网 时间:2024/06/05 07:36

遍历二叉树(traversing binary tree)

1.遍历二叉树的描述

    遍历二叉树是指按某条搜索路径巡访树中每个结点,使得每个结点均被访问一次,而且仅被访问一次。遍历二叉树是二叉树最基本的操作,

也是二叉树其他各种操作的基础、遍历的实质是对二叉树进行线性化的过程,即遍历的结果是将非线性结构的树中结点排成一个线性序列。

1.先序遍历二叉树的操作定义如下:

若二叉树为空,则空操作,否则:

1)访问根结点;

2)先序遍历左子树;

3)先序遍历右子树;

2.中序遍历二叉树的操作定义如下:

若二叉树为空,则空操作,否则:

1)中序遍历左子树;

2)访问根结点;

3)中序遍历右子树;

3.后序遍历二叉树的操作定义如下:

若二叉树为空,则空操作,否则:

1)后序遍历左子树;

2)后序遍历右子树;

3)访问根结点;

例如,如下图所示的二叉树表示下述表达式

a+b*(c-d)-e/f


中序遍历二叉树基本操作的递归算法在二叉链表上的实现,算法将结点的访问简化为数据的输出。

中序遍历的递归算法

[算法描述]
void InOrderTraverse(BiTree T){/*中序遍历二叉树T的递归算法*/if(T){InOrderTraverse(T->lchild);cout<<T->data;InOrderTraverse(T->rchild);}}
只要改变输出语句的顺序,便可类似地实现先序遍历后序遍历的递归算法。

可以利用栈将递归算法改成非递归算法,例如,从中序遍历递归算法执行过程中递归工作栈的状态可见:

1.工作记录中包含两项,其一是递归调用的语句编号,其二数指向根结点的指针,则当栈顶记录中的指针非空时,应遍历左子树,即指向左子树根的指针进栈。

2.若栈顶记录中的指针值为空,应该退至上一层,若是从左子树返回,则应访问当前层(即栈顶记录)中指针所指的根结点。

3.若是从右子树返回,则表明当前层遍历结束,应该继续退栈。从另一个角度看,这意味着遍历右子树时不需要保存当前层的根指针,直接修改栈顶记录中的指针即可。

中序遍历的非递归算法

[算法思想]

设S为一个栈,p为指向根结点的指针。

1)当p非空时,将p所指向的地址进栈,p指向该结点的左孩子

2)当p为空时,弹出栈顶元素并访问,将p指向该结点的右孩子

3)重复前两步,直到栈空且p也为空

[算法描述]

void InOrderTraverse(BiTree T){/*中序遍历二叉树T的非递归算法*/InitStack(S);p=T;q=new BiTNode;while(p || !StackEmpty(S) ){if(p)             /*p非空根指针进栈,遍历左子树*/{Push(S,p);p=p->lchild;}else             /*p为空根指针退栈,访问根结点,遍历右子树*/{Pop(S,q);      cout<<q->data;p=q->rchild;}}}


2.根据遍历序列确定二叉树

由二叉树的先序序列中序序列,或由其后序序列中序序列均能唯一确定一棵二叉树。

例如,已知一棵二叉树的中序序列和后序序列分别是 BDCEAFHG DECBHGFA,请画出这棵二叉树。

[解题思路]

1)由后序遍历特征,根结点必在后序序列尾部,即根结点是A;

2)由中序遍历特征,根结点必在其中间,而且其左部必全部是左子树子孙(BDCE),其右部必全部是右子树子孙(FHG).

3)继而,根据后序中的DECB子树可确定B为A的左孩子,根据HGF子串可确定F为A的右孩子;依次类推,可以唯一确定一棵二叉树。

但是,由一棵二叉树的先序序列和后序序列不能唯一确定一棵二叉树,因为无法确定左右子树两部分。

例如,如果有先序序列AB,后序序列BA,因为无法确定B为左子树还是右子树,所以可得到图所示的两颗不用的二叉树。

3.二叉树遍历算法的应用

“遍历”是二叉树各种操作的基础,假设访问结点的具体操作不仅仅局限于输出结点数据域的值,而把“访问”延伸到对结点的判别、计数等其他操作

,可以解决一些关于二叉树的其他实际问题。如在遍历过程中生成结点,这样便可以建立二叉树的存储结构。

1)创建二叉树的存储结构——二叉链表

为简化问题,设二叉树中结点的元素均为一个单字符。假设按先序遍历的顺序建立二叉链表,T为指向根结点的指针:首先输入一个根结点,若输入是一个

“#”字符,则表明该二叉树为空树,即T为NULL;否则输入的该字符赋给T->data,之后依次递归建立它的左子树T->lchild和右子树T->rchild。例如下图,读入

字符的顺序为:ABC ## DE # G ## F ###(其中#表示空树),可建立相应的二叉链表。


 先序遍历的顺序建立二叉链表
[算法描述]
void CreateBiTree(BiTree &T){/*按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T*/cin>>ch;if(ch == '#') T=NULL;else{T=new BiTNode;T->data=ch;CreateBiTree(T->lchild);CreateBiTree(T->rchild);}}

2)计算二叉树的深度

二叉树的深度为树中结点的最大层次。如果是空树,则深度为0;否则,递归计算左子树的深度记为m,递归计算右子树的深度记为n,二叉树的深度则为m

与n的较大者加1.显然,这是在后序遍历二叉树的基础上进行的运算。

[算法描述]

int Depth(BiTree T){if(T == NULL) return 0;    /*如果是空树,深度为0,递归结束*/else{m=Depth(T->lchild);   /*递归计算左子树的深度记为m*/n=Depth(T->rchild);   /*递归计算右子树的深度记为n*/return m>n?m+1:n+1;   /*二叉树的深度为m与n的较大者加1*/}}

3)统计二叉树中结点的个数

如果是空树,则结点个数为0;否则,结点个数为 左子树的结点个数加上右子树的结点个数再加上1。

[算法描述]
int NodeCount(BiTree T){if(T == NULL)return 0;         /*如果是空,则结点个数为0,递归结束*/else                           /*否则结点个数为左子树的结点个数+右子树的结点个数+1*/{return NodeCount(T->lchild)+NodeCount(T->rchild)+1;}}

[完整代码]

#include<iostream>using namespace std;typedef struct BiTNode{      char data;                  /*结点数据域*/      struct BiTNode *lchild,*rchild;   /*左右孩子指针*/}BiTNode,*BiTree;int n,m;void CreateBiTree(BiTree &T){char ch;/*按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T*/cin>>ch;if(ch == '#') T=NULL;else{T=new BiTNode;T->data=ch;CreateBiTree(T->lchild);CreateBiTree(T->rchild);}}int Depth(BiTree T){if(T == NULL) return 0;    /*如果是空树,深度为0,递归结束*/else{m=Depth(T->lchild);   /*递归计算左子树的深度记为m*/n=Depth(T->rchild);   /*递归计算右子树的深度记为n*/return m>n?m+1:n+1;   /*二叉树的深度为m与n的较大者加1*/}}int NodeCount(BiTree T){if(T == NULL)return 0;         /*如果是空,则结点个数为0,递归结束*/else                           /*否则结点个数为左子树的结点个数+右子树的结点个数+1*/{return NodeCount(T->lchild)+NodeCount(T->rchild)+1;}}void InOrderTraverse(BiTree T){/*中序遍历二叉树T的递归算法*/if(T){InOrderTraverse(T->lchild);cout<<T->data<<" "; InOrderTraverse(T->rchild);}}int main(){BiTree T;cout<<"Input the Binary Tree 's node:"<<endl;/*sample input:ABC ## DE # G ## F ###*/CreateBiTree(T);cout<<"InOrderTraverse: "<<endl;InOrderTraverse(T);cout<<"\nThe Depth:"<<Depth(T)<<"\t The sum's node:"<<NodeCount(T)<<endl;getchar();return 0;}
[运行结果]




1 0
原创粉丝点击