在看慕课上面浙大数据结构时很巧合的想到的写法,感谢浙大陈越、何钦铭老师:
一个二叉树的遍历分前中后序的遍历,这里前中后序是如何遍历的就不多说了。
先给大家看这张图:
按照读出来的顺序是前序遍历,正好是第一次经过该节点
按照读出来的顺序是中序遍历,正好是第二次经过该节点
按照读出来的顺序是后序遍历,正好是第三次经过该节点
那么我们的出来一个结论:按照第1、2、3次经过该节点读出来的顺序就是二叉树的 前、中、后 遍历了,且每个节点被经过了3次
那么我们可以用一个栈存放这些路径上的节点,另一个栈存放对应位置的节点是第几次经过,那么不就能实现前中后序的非递归的遍历了嘛:
typedef struct Tree
{
char data;
struct Tree *lchild;
struct Tree *rchild;
} Tree, *Index_Tree;
/**
对于一个二叉树,整个递归遍历过程每个节点经过了3次;
那么实现非递归遍历时可以:
申请一个栈A用来存贮节点,
另外申请一个栈B用来存贮对应节点位置经过了几次
先把根节点入栈A,并把1入栈B
A栈不为空就一直循环:
当第一次访问一个节点时,先访问它的左子树:
if 为空
B栈顶元素置为2, 因为左子树为空,说明再次访问到了当前节点;
else
左子树入栈A,并1入栈B 因为第一次访问到左子树
当第二次访问到一个节点时,访问它的右子树;
if 为空
B栈顶元素置3 因为右子树为空,说明又返回到了当前节点;
else
将右子树入栈A,并1入栈B 因为右子树第一次被访问到
当第三次访问到一个节点时
让它出栈, 即A、B栈顶元素出栈
并且 在上面的基础上,B栈顶元素+1 因为又再次访问到该元素了
**/
void Stack_Pri_Order(Index_Tree T, int x) ///x为1时前序遍历,x为2时中序遍历, x为3时后序遍历
{
if(!T) ///二叉树不存在返回
return ;
Index_Tree p;
stack<Index_Tree> node;
stack<int> flag;
node.push(T);
flag.push(1);
while(!node.empty())
{
if(flag.top() == 1) ///第一次访问该节点
{
p = node.top();
if(x == 1)
printf("%c", p->data);
if(!p->lchild)
{
flag.pop();
flag.push(2);
}
else
{
node.push(p->lchild);
flag.push(1);
}
}
else if(flag.top() == 2) ///第二次访问该节点
{
p = node.top();
if(x == 2)
printf("%c", p->data);
if(!p->rchild)
{
flag.pop();
flag.push(3);
}
else
{
node.push(p->rchild);
flag.push(1);
}
}
else ///第三次访问该节点
{
p = node.top();
if(x == 3)
printf("%c", p->data);
node.pop();
flag.pop();
if(!flag.empty()) ///如果根节点没有出来,就要让现在的栈顶元素+1
{
int a = flag.top();
flag.pop();
flag.push(++a);
}
}
}
return ;
}