在二叉树的一些应用中,常常要求在树中查找具有某种特征的结点,或者对树中全部结点进行某种处理。这就提出了遍历二叉树(traversing binary tree)的问题,即如何按某条路径巡访树中的每个结点,使得每个结点均被访问一次,而且仅被访问一次。"访问"的含义很广,可以是对结点作各种处理,如输出结点的信息等。
回顾二叉树的递归定义可知,二叉树由根结点、左子树和右子树三个单元组成。因此,遍历这三个单元就能遍历整个二叉树。下面介绍几种常见的二叉树遍历算法。
1. 先序遍历二叉树
先序遍历二叉村的操作定义为:
若二叉树为空,则空操作;否则:
1. 访问根结点;
2. 先序遍历左子树;
3. 先序遍历右子树。
递归算法
void preOrderRecursion(BiTree T) { if (T) { printf("%c ", T->data); preOrderRecursion(T->lchild); preOrderRecursion(T->rchild); } }
非递归算法
假设T是指向二叉树根结点的指针变量,非递归算法是:
若二叉树为空,则返回;否则,令p=T
1. 访问p所指向的结点;
2. 令q=p->rchild,如果q不为空,则q进栈;
3. 令p=p->lchild,如果p不为空,则转1, 否则转4;
4. 退栈到p,转1,直到栈空为止。
参考代码如下所示:
void preOrderIteration(BiTree T) { stack<BiTree> st; st.push(T); while (!st.empty()) { T = st.top(); st.pop(); printf("%c ", T->data); if (T->rchild) st.push(T->rchild); if (T->lchild) st.push(T->lchild); } }
2. 中序遍历二叉树
中序遍历二叉树的操作定义为:
若二叉树为空,则空操作;否则:
1. 中序遍历左子树;
2. 访问根结点;
3. 中序遍历右子树。
递归算法
void inOrderRecursion(BiTree T) { if (T) { inOrderRecursion(T->lchild); printf("%c ", T->data); inOrderRecursion(T->rchild); } }
非递归算法
假设T是指向二叉树的根结点的指针变量,非递归算法是:
若二叉树为空,则返回;否则,令p=T
1. 若p不为空,则p进栈,p=p->lchild;
2. 否则(即p为空),退栈到p,访问p所指向的结点;
3. 令p=p->rchild,转1。
参考代码如下所示:
void inOrderIteration(BiTree T) { stack<BiTree> st; while (T || !st.empty()) { if (T != NULL) { st.push(T); T = T->lchild; } else { T = st.top(); st.pop(); printf("%c ", T->data); T = T->rchild; } } }
3. 后序遍历二叉树
后序遍历二叉树的操作定义为:
若二叉树为空,则空操作;否则:
1. 后序遍历左子树;
2. 后序遍历右子树;
3. 访问根结点
递归算法
void postOrderRecursion(BiTree T) { if (T) { postOrderRecursion(T->lchild); postOrderRecursion(T->rchild); printf("%c ", T->data); } }
非递归算法
4. 层次遍历二叉树
层次遍历二叉树,是从根结点开始遍历,按层次次序"自上而下,从左至右"访问树中的各个结点。
为保证是按层次遍历,必须设置一个队列,初始化为空。设T是指向根结点的指针变量,层次遍历非递归算法是:
若二叉树为空,则返回;否则令p=T,p入队:
1. 队首元素出队到p;
2. 访问p所指向的结点;
3. 将p所指向的结点的左、右子结点依次入队。
直到队空为止。
参考代码如下所示: