二叉树的3中遍历策略,关键在于处理节点的时机不同:前序遍历是遇到节点时处理,中序是处理完左节点后再处理,而后序是在处理完左右节点后再处理。
使用非递归方法实现时,除了记录当前的节点的访问栈,还需要记录当前节点的状态。对于每一个节点,我们用0来表示尚未处理左右子节点,1表示仅仅处理完毕左节点,2表示左右节点都处理完毕。那么,前序,中序,后序遍历的唯一不同,无非是对节点处理的时机不同而已。
const int MAX=20;
typedef struct Node
{
char data;
struct Node*lchild;
struct Node*rchild;
}BiTreeNode;
const int STATE_NONE=0;//尚未处理任何一个节点
const int STATE_LEFT_DONE=1;//处理完左节点
const int STATE_LEFT_RIGHT_DONE=2;//左右节点都已经处理完
/*
算法说明:初始时放入根节点,将其标记为左右节点尚未处理的状态
每个循环,从栈中取出一个节点和其状态,根据其当前状态转移到下一个状态
(很显然,你可以从状态转换机的角度解读这个算法)。
状态转换规则: STATE_NONE-->STATE_LEFT_DONE-->STATE_LEFT_RIGTH_DONE-->弹出栈
伴随状态的变化,还需要相应的操作,如将左右子节点放入栈中,或者将当前节点弹出栈;
最重要的一点是,当当前节点的状态符合处理状态的要求时,就会处理该节点。
*/
void travese(BiTreeNode*T,int when)
{
if(when!=STATE_NONE||when!=STATE_LEFT_DONE||when!=STATE_LEFT_RIGHT_DONE)
{
printf("状态输入有误,请重新输入");
exit(1);
}
BiTreeNode*Stack[MAX]; //保存节点的栈
int stackState[MAX]; //保存节点状态的栈
int top=0;
Stack[++top]=T; //根节点入栈
stackState[top]=STATE_NONE; //根节点状态入栈
while(top>0)
{
BiTreeNode *p=Stack[top];
int state=stackState[top];
if(state==when) //当前状态可以处理节点
printf("%2c",p->data);
//3中状态之间的转换
switch(state)
{
case STATE_NONE:
stackState[top]=STATE_LEFT_DONE;
if(p->lchild)
{
Stack[++top]=p->lchild;
stackState[top]=STATE_NONE;
}
break;
case STATE_LEFT_DONE:
stackState[top]=STATE_LEFT_RIGHT_DONE;
if(p->rchild)
{
Stack[++top]=p->rchild;
stackState[top]=STATE_NONE;
}
break;
case STATE_LEFT_RIGHT_DONE:
top--;
break;
}
}
}