1、二叉树遍历
二叉树遍历包含深度优先遍历和广度优先遍历。实现的方式有递归方式和非递归方式。递归方式较直观,本文使用非递归方式:深度优先遍历使用栈结构,广度优先遍历使用队列方式。
(1)深度优先遍历
深度优先遍历就是从根节点开始,访问子节点,然后访问子节点的子节点,直到叶子节点。
(1-1)深度优先遍历类型
1. 中序遍历
若根节点为空,则算法结束;
中序遍历根结点的左子树;
访问根结点;
中序遍历根结点的右子树。
2. 前序遍历
若根节点为空,则算法结束。
访问根结点;
前序遍历根结点的左子树;
前序遍历根结点的右子树。
3. 后序遍历
若根节点为空,则算法结束。
后序遍历根结点的左子树;
后序遍历根结点的右子树;
访问根结点。
(1-2)非递归深度优先遍历方式
非递归遍历方式:
使用栈结构(栈是实现递归的常用的结构)来实现,利用一个栈来记下待遍历的结点,等待之后的使用(访问或者指引子节点)。
1) 前序遍历
从根节点开始,每见到一个结点,就访问该结点,并把此结点推入栈中,然后下降去遍历它的左子树。遍历完它的左子树后,从栈顶取出这个结点,再去遍历该结点的右子树。
2) 中序遍历
从根节点开始,每见到一个结点,就把它放入栈中,并去遍历它的左子树。遍历完左子树后,从栈顶取出这个节点并访问,然后遍历该节点的右子树。
3)后序遍历
从根节点开始,每见到一个结点,就把它放入栈中,遍历它的左子树。遍历结束后,还不能访问处于栈顶的该结点,而是要先遍历该结点的右子树。遍历完右子树后才能从栈顶取出该结点并访问。(可对节点设置状态,标识为Left表示开始过左子树遍历,标识为Right表示开始过左子树遍历)
4) 简化的前序遍历
从根节点开始,每见到一个结点,就访问该结点,并把此结点的非空右结点推入栈中,然后下降去遍历它的左子树。遍历完左子树后,从栈顶取出一个节点,再从该节点开始前序遍历。
(2)广度优先遍历
非递归遍历方式:
使用队列来实现的,一层层遍历,先从二叉树的第一层(根结点)开始,自上至下逐层遍历;在同一层中,按照从左到右的顺序对结点逐一访问。
按照从根结点至叶结点、从左子树至右子树的次序访问二叉树的结点。
步骤:
1)把根结点入列队;
2)当队列为非空时,循环执行步骤3到步骤5,否则结束遍历
3)出队列取得一个结点,访问该结点
4)若该结点的左节点非空,则将该结点放到入队列末尾
5)若该结点的右节点非空,则将该结点放到入队列末尾
2、图的遍历
图的遍历包含深度优先遍历和广度优先遍历。非递归方式实现:深度优先遍历使用栈结构,广度优先遍历使用队列方式。
(1)深度优先遍历
图的深度方式是类似深度优先遍历二叉树的前序遍历方式。从图的某个顶点v0出发,访问v0,并放置到节点栈中,然后选择一个与v0相邻且没被访问过的节点vi访问,再把vi放入节点栈中,以此类推。如果当前被访问过的节点的所有邻接节点都已被访问,则回退到已被访问的节点栈中最后一个有未被访问的相邻节点的节点wi,从wi的未被访问的节点开始再按同样的方法向前遍历,直到节点栈中没有节点,则表示遍历完成。
(2)广度优先遍历
图的广度优先遍历类似二叉树的广度优先遍历。从图的某个节点出发(作为根节点),先访问初始点v0,并将其标记为已访问,接着访问v0的所有未被访问过的邻接点v1,v2, …, vt,标记已访问过且依次放到队列中,然后从队列头获取一个节点,访问其的未被访问过的邻接点,标记已访问过且依次放到队列中,以此类推,直到队列为空(且当前节点已访问)。