题目:
递归和非递归俩种方法实现二叉树的前序遍历。
思路一:
对二叉树的递归遍历我相信大家只要学了数据结构后应当都很容易就能写出,这里主要是讨论二叉树的非递归写法。按照二叉树前序遍历的定义,无论是访问整棵树还是其子树,均应该遵循先访问根结点,然后访问根结点的左子树,最后访问根结点的右子树的。在整个二叉树前序遍历的过程中,程序始终要做的工作分成俩个部分:(借用辅助栈来实现)
1. 当前正在处理的树(子树)
2. 保存在栈中等待处理的部分。
当栈中元素位于栈顶即将出栈时,意味着其根结点和左子树已访问完成,出栈后,进入其右子树进行访问。
代码如下:
/*-------------------------------
Copyright by yuucyf. 2011.09.06
--------------------------------*/
#include "stdafx.h"
#include <assert.h>
#include <iostream>
#include <stack>
using namespace std;
typedef struct tagBSTreeNode
{
int nValue;
tagBSTreeNode *psLeft;
tagBSTreeNode *psRight;
tagBSTreeNode()
{
psLeft = psRight = 0;
nValue = 0;
}
}S_BSTreeNode;
void AddBSTreeNode(S_BSTreeNode *&psRoot, int nValue)
{
if (NULL == psRoot)
{
psRoot = new S_BSTreeNode;
assert(psRoot);
psRoot->nValue = nValue;
return;
}
if (psRoot->nValue < nValue)
AddBSTreeNode(psRoot->psRight, nValue);
else
AddBSTreeNode(psRoot->psLeft, nValue);
}
void PreOrder_Recursion(const S_BSTreeNode *psRoot)
{
if (NULL == psRoot)
return;
cout << psRoot->nValue << " ";
PreOrder_Recursion(psRoot->psLeft);
PreOrder_Recursion(psRoot->psRight);
}
void PreOrder_Not_Recursion(S_BSTreeNode *psRoot)
{
stack<S_BSTreeNode *> stackNode;
S_BSTreeNode *psCurNode = psRoot;
while ((!stackNode.empty()) || (psCurNode != NULL))
{
if (psCurNode != NULL)
{
while (psCurNode)
{
cout << psCurNode->nValue << " ";
stackNode.push(psCurNode);
psCurNode = psCurNode->psLeft;
}
}
else
{
psCurNode = stackNode.top();
stackNode.pop();
psCurNode = psCurNode->psRight;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
S_BSTreeNode *psRoot = NULL;
AddBSTreeNode(psRoot, 8);
AddBSTreeNode(psRoot, 6);
AddBSTreeNode(psRoot, 4);
AddBSTreeNode(psRoot, 5);
AddBSTreeNode(psRoot, 12);
AddBSTreeNode(psRoot, 10);
AddBSTreeNode(psRoot, 15);
AddBSTreeNode(psRoot, 13);
AddBSTreeNode(psRoot, 14);
cout << "递归遍历的结果为:" << endl;
PreOrder_Recursion(psRoot);
cout << endl;
cout << "非递归遍历的结果为:" << endl;
PreOrder_Not_Recursion(psRoot);
cout << endl;
//Don't forget to free memory.
return 0;
}
扩展:
如果要求是非递归后序遍历呢?非递归后序稍微有点复杂。按照二叉树后序遍历的定义,无论是访问整棵树还是起子树,均应该遵循先访问根结点左子树,然后访问根结点的右子树,最后访问根结点。值得注意的是,当一个元素位于栈顶即将处理的是,其左子树的访问一定完成,如果其右子树不为空,接下来应该进入其右子树访问,但此时该栈顶元素时不能出栈的,因为它作为根结点,其本身的值还未被访问。只有等到其右子树也访问完成后,该栈顶元素才能出栈,并输出它的值。 因此,在二叉树后序遍历的算法中,必须每个节点维护一个类型为int的整数nTag,
其每个元素(节点)的nTag取值为0 或1,用于标识栈中每个元素的状态。
1. 当一个元素刚进栈时,其对应的nTag 值置为0;
2. 当它位于栈顶即将被处理时,其nTag 值为0.意味着应该访问其右子树,于是将右子树作为当前处理的对象,此时该栈顶元素仍应该保留在栈中,并将其对应的nTag 值改为1.
3. 当其右子树访问完成后,该元素又一次位于栈顶,而此时其nTag 值为1,意味着其右子树已访问完成,接下来,应该直接访问的就是它,将其出栈。
代码如下:
void PostOrder_Not_Recursion(S_BSTreeNode *psRoot)
{
stack<S_BSTreeNode *> stackNode;
S_BSTreeNode *psCurNode = psRoot;
while ((!stackNode.empty()) || (psCurNode != NULL))
{
if (psCurNode != NULL)
{
while (psCurNode /*&& psCurNode->nTag != 1*/)
{
stackNode.push(psCurNode);
psCurNode = psCurNode->psLeft;
}
}
psCurNode = stackNode.top();
while ((!stackNode.empty()) && (psCurNode->nTag == 1))
{
cout << psCurNode->nValue << " ";
stackNode.pop();
if (stackNode.empty())
psCurNode = NULL;
else
psCurNode = stackNode.top();
}
if (!stackNode.empty())
{
psCurNode->nTag = 1;
psCurNode = psCurNode->psRight;
}
else
psCurNode = NULL;
}
}