1、二叉树的遍历,一、问题的提出,二、先左后右的遍历算法,三、算法的递归描述,四、遍历算法的应用举例,顺着某一条搜索路径巡访二叉树 中的结点,使得每个结点均被访问一 次,而且仅被访问一次。,一、问题的提出,“访问”的含义可以很广,如:输出结 点的信息等。,“遍历”是任何类型均有的操作, 对线性结构而言,只有一条搜索路 径(因为每个结点均只有一个后继), 故不需要另加讨论。而二叉树是非 线性结构,,每个结点有两个后继, 则存在如何遍历即按什么样的搜索 路径进行遍历的问题。,对“二叉树”而言,可以有三条搜索路径:,1先上后下的按层次遍历; 2先左(子树)后右(子树)的遍历; 3先右(子树)后左(子树)
2、的遍历。,二、先左后右的遍历算法,先(根)序的遍历算法,中(根)序的遍历算法,后(根)序的遍历算法,根,左 子树,右 子树,根,根,根,根,根,若二叉树为空树,则空操作;否则, (1)访问根结点; (2)先序遍历左子树; (3)先序遍历右子树。,先(根)序的遍历算法:,若二叉树为空树,则空操作;否则, (1)中序遍历左子树; (2)访问根结点; (3)中序遍历右子树。,中(根)序的遍历算法:,若二叉树为空树,则空操作;否则, (1)后序遍历左子树; (2)后序遍历右子树; (3)访问根结点。,后(根)序的遍历算法:,例如:,先序序列:,中序序列:,后序序列:,A B C D E F G H K
3、,B D C A E H G K F,D C B H K G F E A,三、算法的递归描述,void Preorder (BiTree T,void( *visit)(TElemType/ 遍历右子树 ,四、遍历算法的应用举例,2、统计二叉树中叶子结点的个数,3、求二叉树的深度(后序遍历),4、复制二叉树(后序遍历),5、建立二叉树的存储结构,1、查询二叉树中某个结点,1. 在二叉树不空的前提下,和根结点的元素进行比较,若相等,则找到返回 TRUE;,2. 否则在左子树中进行查找,若找到, 则返回 TRUE;,3. 否则继续在右子树中进行查找,若找到,则返回 TRUE,否则返回 FALSE;
4、,Status Preorder (BiTree T, ElemType x, BiTree &p) / 若二叉树中存在和 x 相同的元素,则 p 指向该结点并返回 OK, / 否则返回 FALSE ,if (T) if (T-data=x) p = T; return OK, /if else return FALSE;,else if (Preorder(T-lchild, x, p) return OK;else return(Preorder(T-rchild, x, p) ; /else,2、统计二叉树中叶子结点的个数,算法基本思想:,先序(或中序或后序)遍历二叉树,在遍历过程中查找
5、叶子结点,并计数。 由此,需在遍历算法中增添一个“计数”的参数,并将算法中“访问结点” 的操作改为:若是叶子,则计数器增1。,void CountLeaf (BiTree T, int / if / CountLeaf,int CountLeaf (BiTree T) /返回指针T所指二叉树中所有叶子结点个数if (!T ) return 0;if (!T-lchild /else / CountLeaf,int Count (BiTree T) /返回指针T所指二叉树中所有结点个数if (!T ) return 0;if (!T-lchild /else / CountLeaf,3、求二叉树
6、的深度(后序遍历),算法基本思想:,从二叉树深度的定义可知,二叉树的深度应为其左、右子树深度的最大值加1。由此,需先分别求得左、右子树的深度,算法中“访问结点”的操作为:求得左、右子树深度的最大值,然后加 1 。,首先分析二叉树的深度和它的左、右子树深度之间的关系。,int Depth (BiTree T ) / 返回二叉树的深度if ( !T ) depthval = 0;else depthLeft = Depth( T-lchild );depthRight= Depth( T-rchild );depthval = 1 + (depthLeft depthRight ?depthLef
7、t : depthRight); return depthval; ,void Depth(BiTree T , int level, int / 调用之前 level 的初值为 1。/ dval 的初值为 0.,4、复制二叉树,其基本操作为:生成一个结点。,根元素,T,左子树,右子树,NEWT,左子树,右子树,左子树,右子树,(后序遍历),BiTNode *GetTreeNode(TElemType item, BiTNode *lptr , BiTNode *rptr )if (!(T = new BiTNode)exit(1);T- data = item;T- lchild = lpt
8、r; T- rchild = rptr;return T; ,生成一个二叉树的结点 (其数据域为item,左指针域为lptr,右指针域为rptr),BiTNode *CopyTree(BiTNode *T) if (!T ) return NULL;if (T-lchild ) newlptr = CopyTree(T-lchild); /复制左子树else newlptr = NULL;if (T-rchild ) newrptr = CopyTree(T-rchild); /复制右子树else newrptr = NULL;newT = GetTreeNode(T-data, newlpt
9、r, newrptr);return newT; / CopyTree,例如:下列二叉树的复制过程如下:,newT,5、建立二叉树的存储结构,不同的定义方法相应有不同的存储结构的建立算法,以字符串的形式 “根 左子树 右子树” 定义一棵二叉树,例如:,以空白字符“ ”表示,A(B( ,C( , ),D( , ),空树,只含一个根结点的二叉树,A,以字符串“A ”表示,以下列字符串表示,Status CreateBiTree(BiTree / CreateBiTree,A B C D,A,B,C,D,上页算法执行过程举例如下:,A,T,B,C,D,scanf(,按给定的表达式建相应二叉树, 由先
10、缀表示式建树 例如:已知表达式的先缀表示式-+ a b c / d e, 由原表达式建树 例如:已知表达式 (a+b)c d/e,对应先缀表达式 -+ a b c / d e的二叉树,a,b,c,d,e,-,+,/,特点:操作数为叶子结点,运算符为分支结点,scanf( ,由先缀表示式建树的算法的基本操作:,a+b,(a+b)c d/e,a+bc,分析表达式和二叉树的关系:,(a+b)c,基本操作:,scanf( ,void CrtExptree(BiTree / CrtExptree, ,switch (ch) case ( : Push(S, ch); break;case ) : Pop
11、(S, c);while (c!= ( ) CrtSubtree( t, c); / 建二叉树并入栈Pop(S, c) break; defult : / switch, ,while(!Gettop(S, c) ,建叶子结点的算法为:,void CrtNode(BiTree ,建子树的算法为:,void CrtSubtree (Bitree ,仅知二叉树的先序序列“abcdefg” 不能唯一确定一棵二叉树,,由二叉树的先序和中序序列建树,如果同时已知二叉树的中序序列“cbdaegf”,则会如何?,二叉树的先序序列,二叉树的中序序列,左子树,左子树,右子树,右子树,根,根,a b c d e
12、f g,c b d a e g f,例如:,a,a,b,b,c,c,d,d,e,e,f,f,g,g,a,b,c,d,e,f,g,先序序列中序序列,void CrtBT(BiTreeelse / / CrtBT, ,if (!(T= new BiTNode) exit(OVERFLOW); T-data = preps; if (k=is) T-Lchild = NULL; else CrtBT(T-Lchild, pre, ino, ps+1, is, k-is ); if (k=is+n-1) T-Rchild = NULL; else CrtBT(T-Rchild, pre, ino, ps+1+(k-is), k+1, n-(k-is)-1 );,