如下图,对图中二叉树遍历:
先序为:ABDNCEFGHIJKLMOQP
中序为:DNBCGFEAHJKILOQMP
后序为:NDGFECBKJQOPMLIHA
假设树节点如下:
struct Node{
char data;
Node *left;
Node *right;
};
递归实现
先序
void preOrder(Node *root){
cout<<root->data;
preOrder(root->left);
preOder(root->right);
}
中序
void inOrder(Node *root){
preOrder(root->left);
cout<<root->data;
preOder(root->right);
}
后序
void postOrder(Node *root){
preOrder(root->left);
preOder(root->right);
cout<<root->data;
}
非递归实现
先序
对于任一结点P:
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。
void preOrderS(Node *root)
{
stack<Node*> s;
Node *p=root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
cout<<p->data<<" ";
s.push(p);
p=p->left;
}
if(!s.empty())
{
p=s.top();
s.pop();
p=p->right;
}
}
}
中序
对于任一结点P,
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束。
void inOrderS(Node *root){
stack<Node*> s;
Node *p=root;
while(p!=NULL||!s.empty()){
while(p!=NULL)){
s.push(p);
p=p->left;
}
if(!s.empty()){
p=s.top();
s.pop();
cout<<p->data;
p=p->right;
}
}
}
后序
因为后序非递归遍历二叉树的顺序是先访问左子树,再访问右子树,最后访问根节点。当用堆栈来存储节点,必须分清返回根节点时,是从左子树返回的,还从右子树返回的。所以,使用辅助指针r,其指向最近访问过的节点。也可以在节点中增加一个标志域,记录是否已被访问。
void PostOrderS(Node *root) {
Node *p = root, *r = NULL;
stack<Node*> s;
while (p!=NULL || !s.empty()) {
if (p!=NULL) {//走到最左边
s.push(p);
p = p->left;
}
else {
p = s.top();
if (p->right!=NULL && p->right != r)//右子树存在,未被访问
p = p->right;
else {
s.pop();
visit(p->val);
r = p;//记录最近访问过的节点
p = NULL;//节点访问完后,重置p指针
}
}//else
}//while
}