题目:给定一颗二叉树,如下图:
要求:
前序遍历输出结果:1 2 4 6 7 5 9 10 3 8
中序遍历输出结果:6 4 7 2 9 5 10 1 3 8
后序遍历输出结果:6 7 4 9 10 5 2 8 3 1
结构如下:
struct Node
{
Node(int val)
:_left(NULL)
,_right(NULL)
,_val(val)
{}
Node* _left;
Node* _right;
int _val;
};
前序遍历
分析:
前序遍历的递归定义:先根节点,后左子树,再右子树。有了中序遍历的基础,不用我再像中序遍历那样引导了吧。
首先,我们遍历左子树,边遍历边打印,并把根节点存入栈中,以后需借助这些节点进入右子树开启新一轮的循环。还得重复一句:所有的节点都可看做是根节点。
void PrevSort_Tree(Node* root)//前序遍历
{
assert(root);
if(root->_left ==NULL&&root->_right ==NULL)
{
cout<<root->_val;
return ;
}
Node* cur=root;
stack<Node*> s;
s.push(root);
while (!s.empty()) //循环结束条件与前两种不一样
{
cout << cur->_val <<" ";
/*
栈的特点:先进后出
先被访问的根节点的右子树后被访问
*/
if (cur->_right )
s.push(cur->_right );
if (cur->_left )
cur = cur->_left ;
else
{//左子树访问完了,访问右子树
cur= s.top();
s.pop();
}
}
cout << endl;
}
中序遍历:
中序遍历的递归定义:先左子树,后根节点,再右子树。如何写非递归代码呢?一句话:让代码跟着思维走。我们的思维是什么?思维就是中序遍历的路径。假设,你面前有一棵二叉树,现要求你写出它的中序遍历序列。如果你对中序遍历理解透彻的话,你肯定先找到左子树的最下边的节点。
void InSort_Tree(Node* root)
{
assert(root);
if(root->_left ==NULL&&root->_right ==NULL)
{
cout<<root->_val;
return ;
}
Node* cur=root;
stack<Node*> s;
while (!s.empty()||cur) //循环结束条件与前两种不一样
{
while(cur)
{
s.push(cur);
cur = cur->_left ;
}
if(!s.empty())
{//左子树访问完了,访问右子树
cur= s.top();
s.pop();
cout<<cur->_val <<" ";
cur=cur->_right ;
}
}
cout << endl;
}
后续遍历:
后序遍历递归定义:先左子树,后右子树,再根节点。后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点;若是位于右子树,则直接访问根节点。
void PostOrderTraverse(Node* root)//非递归后序遍历,用一个标记标记右子树是否访问过
{
if (root == NULL)
return;
stack<Node*> s;
//pCur:当前访问节点,pLastVisit:上次访问节点
Node* pCur, *pLastVisit;
pCur = root;
pLastVisit = NULL;
while (pCur) //先把pCur移动到左子树最下边
{
s.push(pCur);
pCur = pCur->_left ;
}
while (!s.empty()) //走到这里,pCur都是空,
//并已经遍历到左子树底端(看成扩充二叉树,则空,亦是某棵树的左孩子)
{
pCur = s.top();
s.pop();
//一个根节点被访问的前提是:无右子树或右子树已被访问过
if (pCur->_right == NULL || pCur->_right == pLastVisit)
{
cout << pCur->_val <<" ";
//修改最近被访问的节点
pLastVisit = pCur;
}
/*这里的else语句可换成带条件的else if:
else if (pCur->lchild == pLastVisit)//若左子树刚被访问过,则需先进入右子树(根节点需再次入栈)
因为:上面的条件没通过就一定是下面的条件满足。仔细想想!
*/
else
{
//根节点再次入栈
s.push(pCur);
//进入右子树,且可肯定右子树一定不为空
pCur = pCur->_right ;
while (pCur)
{
s.push(pCur);
pCur = pCur->_left ;
}
}
}
cout << endl;
}
代码测试如下:
void test1()
{
BinaryTree t;
Node* node1=new Node(1);
Node* node2=new Node(2);
Node* node3=new Node(3);
Node* node4=new Node(4);
Node* node5=new Node(5);
Node* node6=new Node(6);
Node* node7=new Node(7);
Node* node8=new Node(8);
Node* node9=new Node(9);
Node* node10=new Node(10);
node1->_left=node2;
node1->_right=node3;
node2->_left=node4;
node2->_right=node5;
node3->_left =node8;
node4->_left =node6;
node4->_right=node7;
node5->_left =node9;
node5->_right =node10;
cout<<"PrevSort:";
t.PrevSort_Tree(node1);
cout<<"InSort:";
t.InSort_Tree(node1);
cout<<"PostSort:";
t.PostOrderTraverse(node1);
}
int main()
{
test1();
system("pause");
return 0;
}
层序遍历详见博客:http://blog.csdn.net/wodeqingtian1234/article/details/75646566