——如阅读体验不佳,可转为横屏阅读;如微信无法横屏,可尝试文末方法。
二叉树的遍历:深度优先遍历,包括先序(根)遍历、中序(根)遍历和后序(根)遍历(先序、中序和后序是根相对于左右子树而言,且先左后右。只有二叉树才同时有先序、中序和后序遍历,一般的树无中序遍历);广度优先遍历,包括层次遍历(所有的树都可进行层次遍历)。中序遍历的过程实质上是一个结点(根)进栈和出栈的过程。
二叉树深度优先遍历的递归实现
只有深度优先遍历可用递归实现,广度优先遍历无法用递归实现。在先、中和后序遍历中,均将当前结点作为根结点看待,以根结点为中心实现递归。
先序遍历递归算法
若二叉树非空,则
(1)访问根结点;
(2)先序遍历左子树;
(3)先序遍历右子树。
voidPreOrderTraverse(BiTree r, void (*visit)(BiTree)){ if (r != NULL) { visit(r); PreOrderTraverse(r->lchild, visit); PreOrderTraverse(r->rchild, visit); }}
中序遍历递归算法
若二叉树非空,则
(1)中序遍历左子树;
(2)访问根结点;
(3)中序遍历右子树。
voidMidOrderTraverse(BiTree r, void (*visit)(BiTree)){ if (r != NULL) { MidOrderTraverse(r->lchild, visit); visit(r); MidOrderTraverse(r->rchild, visit); }}
后序遍历递归算法
若二叉树非空,则
(1)后序遍历左子树;
(2)后序遍历右子树;
(3)访问根结点。
voidPostOrderTraverse(BiTree r, void (*visit)(BiTree)){ if (r != NULL) { PostOrderTraverse(r->lchild, visit); PostOrderTraverse(r->rchild, visit); visit(r); }}
对于深度优先遍历的递归实现而言,不管按哪种次序遍历,对含n个结点的二叉树,其时间复杂度均为,所需辅助空间为遍历过程中栈的最大容量,即树的深度(因为栈中存放的是根且这些根从栈底到栈顶,任意相邻的两个根均为父子(非左即右)关系),最坏情况下为n,故空间复杂度也为。
二叉树遍历的非递归实现
遍历类型 | 遍历次序 | 非递归遍历过程 |
广度优先 (队列) | 层次遍历 | 根结点入队→<队列非空>{队首结点出队→出队结点访问→访问结点的非空孩子结点按从左到右的顺序依次入队} |
深度优先 (栈) | 先序遍历 | 根结点入栈→<栈非空>{栈顶结点出栈→出栈结点访问→访问结点的非空孩子结点按从右到左的顺序依次入栈} |
中序遍历 | 根结点入栈→<栈非空>{<栈顶结点非空>栈顶结点的左孩子结点入栈→栈顶空结点出栈→(栈非空){栈顶结点出栈→出栈结点访问→访问结点的右孩子入栈}} |
后序遍历 | 根结点入栈→<栈非空>{<栈顶结点非空>栈顶结点的左孩子结点入栈→[(次栈顶结点存在)[(次栈顶结点非空)次栈顶结点的右孩子结点入栈|(次栈顶结点为空){栈顶和次栈顶空结点出栈→栈顶结点出栈→出栈结点访问→空结点入栈}]|(次栈顶结点不存在)栈顶空结点出栈]} |
说明: (1) 符号说明:“<>”表示循环条件,“()”表示选择条件,“[]”表示互斥,“{}”表示全部,“→or-”表示顺序执行,“|”表示并行执行。 (2) 广度优先遍历(层次遍历)的非递归实现使用队列,深度优先遍历(先序、中序和后序遍历)的非递归实现使用栈。 (3) 广度优先遍历(层次遍历)和深度优先遍历(先序、中序和后序遍历)的非递归实现中均是在结点出队列或栈时对其进行访问。 (4) 深度优先遍历(先序、中序和后序遍历)的非递归实现中,均是通过将栈内连续的空结点数作为标志来判断左右子树是否均已访问完毕:先序遍历时根最先访问,无需等待子树访问完毕,故无需进行标记,因而遍历过程中栈内无空结点;中序遍历时根中间访问,需等待左子树访问完毕,故需要进行标记,因而遍历过程中栈内连续的空结点数为1,后序遍历中根最后访问,需要等待全部子树访问完毕,故需要进行标记,因而遍历过程中栈内连续的空结点数为2(对于n叉树来说为n)。 |
先序遍历序列和中序遍历序列或后序遍历序列和中序遍历序列均可唯一确定一棵二叉树(依据先序或后序序列确定二叉树的根和各任意子树的根;依据中序序列划分左右子树。具体过程为:因先序遍历是先访问根结点D,其次遍历左子树L,最后遍历右子树R,则在先序序列中,第一个结点必是根D;因中序遍历是先遍历左子树L,然后访问根D,最后遍历右子树R,则根结点D将中序序列分割成两部分,在D之前是左子树结点的中序序列,在D之后是右子树结点的中序序列,反过来,根据左子树的中序序列中结点个数,又可将前序序列除根以外分成左子树的前序序列和右子树的前序序列两部分,以此类推,便可递归得到整棵二叉树。)。
用二叉树表示表达式的递归定义如下:若表达式为数或简单变量,则相应的二叉树中仅有一个根结点,其数据域存放该表达式信息;若表达式=<第一操作数><运算符><第二操作数>,则相应二叉树中以左子树表示第一操作数,右子树表示第二操作数,根结点的数据域存放运算符(若为一元运算符,则左子树为空)。操作数本身又为表达式。
对算数表达式的二叉树进行先序遍历、中序遍历和后序遍历,可分别得到表达式的前缀表示(波兰式)、中缀表示(与算数表达式的区别是仅不含括号而已)和后缀表示(逆波兰式)。
——可选择“【右上角···】→【在浏览器中打开】”进行横屏阅读。