稍微解释一下:
先序遍历。将根节点入栈,考察当前节点(即栈顶节点),先访问当前节点,然后将其出栈(已经访问过,不再需要保留),然后先将其右孩子入栈,再将其左孩子入栈(这个顺序是为了让左孩子位于右孩子上面,以便左孩子的访问先于右孩子;当然如果某个孩子为空,就不用入栈了)。如果栈非空就重复上述过程直到栈空为止,结束算法。
中序遍历。将根节点入栈,考察当前节点(即栈顶节点),如果其左孩子未被访问过(有标记),则将其左孩子入栈,否则访问当前节点并将其出栈,再将右孩子入栈。如果栈非空就重复上述过程直到栈空为止,结束算法。
后序遍历。将根节点入栈,考察当前节点(即栈顶节点),如果其左孩子未被访问过,则将其左孩子入栈,否则如果其右孩子未被访问过,则将其右孩子入栈,如果都已经访问过,则访问其自身,并将其出栈。如果栈非空就重复上述过程直到栈空为止,结束算法。
其实,这只不过是保证了先序中序后序三种遍历的定义。对于先序,保证任意一个节点先于其左右孩子被访问,还要保证其左孩子先于右孩子被访问。对于中序,保证任意一个节点,其左孩子先于它被访问,右孩子晚于它被访问。对于后序,保证任意一个节点的左孩子右孩子都先于它被访问,其中左孩子先于右孩子被访问。如是而已。
附 教科书上实现方式:
先序遍历。将根节点入栈,考察当前节点(即栈顶节点),先访问当前节点,然后将其出栈(已经访问过,不再需要保留),然后先将其右孩子入栈,再将其左孩子入栈(这个顺序是为了让左孩子位于右孩子上面,以便左孩子的访问先于右孩子;当然如果某个孩子为空,就不用入栈了)。如果栈非空就重复上述过程直到栈空为止,结束算法。
中序遍历。将根节点入栈,考察当前节点(即栈顶节点),如果其左孩子未被访问过(有标记),则将其左孩子入栈,否则访问当前节点并将其出栈,再将右孩子入栈。如果栈非空就重复上述过程直到栈空为止,结束算法。
后序遍历。将根节点入栈,考察当前节点(即栈顶节点),如果其左孩子未被访问过,则将其左孩子入栈,否则如果其右孩子未被访问过,则将其右孩子入栈,如果都已经访问过,则访问其自身,并将其出栈。如果栈非空就重复上述过程直到栈空为止,结束算法。
其实,这只不过是保证了先序中序后序三种遍历的定义。对于先序,保证任意一个节点先于其左右孩子被访问,还要保证其左孩子先于右孩子被访问。对于中序,保证任意一个节点,其左孩子先于它被访问,右孩子晚于它被访问。对于后序,保证任意一个节点的左孩子右孩子都先于它被访问,其中左孩子先于右孩子被访问。如是而已。
代码里应该体现得比较清楚。这里不光给出了非递归版本,也给出了递归版本。
这里需要强调一下:相对于教科书上实现方式,这种实现方式,visit和stack.pop总是结合在一起,这种非递归栈管理比较容易接受,而教科书上visit和pop可能是割裂的。最后会附上教科书上的实现方式。
void PreOrderNoRecursion(TreePtr p)
{
cout<<"PreOrderNoRecursion\n";
stack<TreeNode> stk;
TreeNode t = *p;
stk.push(t);
while (!stk.empty())
{
t = stk.top();
stk.pop();
cout<<t.data<<" ";
if (t.right != NULL)
{
stk.push((*t.right));
}
if (t.left != NULL)
{
stk.push((*t.left));
}
}
}
void InOrderNoRecursion(TreePtr p)
{
cout<<"InOrderNoRecursion\n";
stack<TreeNode> stk;
TreeNode t = *p;
stk.push(t);
while (!stk.empty())
{
if (stk.top().flag == 0)
{
stk.top().flag++;
if (stk.top().left != NULL)
{
stk.push(*(stk.top().left));
}
}
else
{
t = stk.top();
stk.pop();
cout<<t.data<<" ";
if (t.right != NULL)
{
stk.push(*(t.right));
}
}
}
}
void PostOrderNoRecursion(TreePtr p)
{
cout<<"PostOrderNoRecursion\n";
stack<TreeNode> stk;
TreeNode t = *p;
stk.push(t);
while (!stk.empty())
{
if (stk.top().flag == 0)
{
stk.top().flag++;
if (stk.top().left != NULL)
{
stk.push(*(stk.top().left));
}
}
else if (stk.top().flag == 1)
{
stk.top().flag++;
if (stk.top().right != NULL)
{
stk.push(*(stk.top().right));
}
}
else
{
cout<<stk.top().data<<" ";
stk.pop();
}
}
}
附 教科书上实现方式:
1.先序遍历非递归算法
void PreOrderUnrec(Bitree *t)
{
Stack s;
StackInit(s);
Bitree *p=t;
while (p!=NULL || !StackEmpty(s))
{
while (p!=NULL) //遍历左子树
{
visite(p->data);
push(s,p);
p=p->lchild;
}
if (!StackEmpty(s)) //通过下一次循环中的内嵌while实现右子树遍历
{
p=pop(s);
p=p->rchild;
}//endif
}//endwhile
}
2.中序遍历非递归算法
void InOrderUnrec(Bitree *t)
{
Stack s;
StackInit(s);
Bitree *p=t;
while (p!=NULL || !StackEmpty(s))
{
while (p!=NULL) //遍历左子树
{
push(s,p);
p=p->lchild;
}
if (!StackEmpty(s))
{
p=pop(s);
visite(p->data); //访问根结点
p=p->rchild; //通过下一次循环实现右子树遍历
}//endif
}//endwhile
}
3.后序遍历非递归算法
typedef enum{L,R} tagtype;
typedef struct
{
Bitree ptr;
tagtype tag;
}stacknode;
typedef struct
{
stacknode Elem[maxsize];
int top;
}SqStack;
void PostOrderUnrec(Bitree t)
{
SqStack s;
stacknode x;
StackInit(s);
p=t;
do
{
while (p!=null) //遍历左子树
{
x.ptr = p;
x.tag = L; //标记为左子树
push(s,x);
p=p->lchild;
}
while (!StackEmpty(s) && s.Elem[s.top].tag==R)
{
x = pop(s);
p = x.ptr;
visite(p->data); //tag为R,表示右子树访问完毕,故访问根结点
}
if (!StackEmpty(s))
{
s.Elem[s.top].tag =R; //遍历右子树
p=s.Elem[s.top].ptr->rchild;
}
}while (!StackEmpty(s));
}//PostOrderUnrec
我自己的实现:
#include <iostream>
#include <stack>
using namespace std;
struct Node
{
int data;
Node* l;
Node* r;
bool visitedleft;
bool visitedright;
Node(int d):data(d),l(NULL),r(NULL),visitedleft(false),visitedright(false){}
};
void preOrder(Node* root)
{
if(NULL == root)
return;
stack<Node*> st;
st.push(root);
while(!st.empty() )
{
Node* tmp = st.top();
st.pop();
cout << tmp->data << endl;
if(tmp->r)
{
st.push(tmp->r);
}
if(tmp->l)
st.push(tmp->l);
}
}
void inOrder(Node* root)
{
if(NULL == root)
return ;
stack<Node*> st;
st.push(root);
while(!st.empty() )
{
Node* tmp = st.top();
if(tmp->l && !tmp->visitedleft)
{
st.top()->visitedleft = true;
st.push(tmp->l);
}
else
{
Node* v = st.top();
st.pop();
cout << v->data << endl;
if(v->r)
{
st.push(v->r);
}
}
}
}
void postOrder(Node* root)
{
if(NULL == root)
return ;
stack<Node*> st;
st.push(root);
while(!st.empty() )
{
Node* tmp = st.top();
if(tmp->l && !tmp->visitedleft)
{
st.top()->visitedleft = true;
st.push(tmp->l);
}
else
{
if(tmp->r && !tmp->visitedright)
{
st.top()->visitedright = true;
st.push(tmp->r);
}
else
{
st.pop();
cout << tmp->data << endl;
}
}
}
}