二叉树–非递归的 先,中,后 序遍历
题目描述
给定一颗二叉树的逻辑结构如下图,(先序遍历的结果,空树用字符‘#’表示,例如AB#C##D##),建立该二叉树的二叉链式存储结构,并输出该二叉树的先序遍历、中序遍历和后序遍历结果。
输入
- 第一行输入一个整数t,表示有t个二叉树
- 第二行起输入每个二叉树的先序遍历结果,空树用字符‘#’表示,连续输入t行。
输出
- 输出每个二叉树的先序遍历、中序遍历和后序遍历结果。
样例输入
2
AB#C##D##
AB##C##
样例输出
ABCD
BCAD
CBDA
ABC
BAC
BCA
思路:
借助一个栈
一开始先让根节点进栈,然后while(栈非空)
每次循环我们就做这几件事情:
- 取栈顶元素 tp
- 如果 tp 为空指针,那么直接将 tp 弹出,continue 进行下一次循环
- 如果 tp 不空,判断 tp 的 visited 标志是多少
- 如果是 0, 那么 tp 的左孩子进栈, visited += 1
- 如果是 1, 那么 tp 的右孩子进栈, visited += 1
- 如果是 2, 那么 tp 弹出栈
先序遍历,非递归 图示:
初始状态:我们需要把根节点进栈
此时栈中只有一个元素 A
取出栈顶的元素(红色框表示),我们第一个访问的是A
然后因为A是第一次访问,我们将A的左孩子进栈,visited ++
取出栈顶的元素(红色框表示)B, 这次我们访问B
B也是第一次访问,输出B,B左孩子(NULL)进栈,visited ++
这一次栈顶元素是 NULL,直接弹出,然后 continue 掉
弹出了NULL之后栈顶元素又是B了,因为是第二次访问了(对应 visited = 1, 图中把visited +1 之后变为2了),把B的右孩子进栈
这里栈顶是B的右孩子也就是C,visited = 0,我们将他++
第一次访问,因为是先序,我们输出C,然后将C的左孩子进栈
栈顶为C的左孩子NULL,直接弹出
这里栈顶元素又是C了,第二次访问C,C的右孩子进栈
栈顶元素为C的右孩子NULL,直接弹出
弹出了C的右孩子之后栈顶元素又是C了,此时C是第三次被访问到,说明C的左右孩子都访问过了,这时候可以弹出C了
弹出了C之后栈顶元素为B,此时B也是第三次被访问,弹出B
弹出B之后栈顶为A,A是第二次被访问,A的右孩子D进栈
栈顶为D,D是第一次被访问,输出D,然后D的左孩子进栈
栈顶为D的左孩子NULL,弹出
栈顶为D,D是第二次被访问,D的右孩子进栈
D的右孩子NULL,直接弹出
弹出D的右孩子之后栈顶为D,D是第三次被访问,弹出D
弹出D之后栈顶为A,A也是第三次被访问了,弹出A,遍历结束
这种方法,先中后序遍历的不同就是在第几次访问的时候输出
如果是先序,第一次访问就输出
中序:第二次
后序:第三次
先序非递归实现:
#define push push_back
#define pop pop_back
#define top back
void node::DLR()
{
deque<node*> s; // use deque as stack
s.push(this);
while(!s.empty())
{
node* tp = s.top();
if(tp == NULL)
{
s.pop();
continue;
}
if(tp->visited == 0)
{
cout<<tp->data;
tp->visited += 1;
s.push(tp->lchild);
}
else if(tp->visited == 1)
{
tp->visited += 1;
s.push(tp->rchild);
}
else if(tp->visited == 2)
{
s.pop();
}
}
}
中序非递归:
void node::LDR()
{
deque<node*> s; // use deque as stack
s.push(this);
while(!s.empty())
{
node* tp = s.top();
if(tp == NULL)
{
s.pop();
continue;
}
if(tp->visited == 0)
{
tp->visited += 1;
s.push(tp->lchild);
}
else if(tp->visited == 1)
{
cout<<tp->data;
tp->visited += 1;
s.push(tp->rchild);
}
else if(tp->visited == 2)
{
s.pop();
}
}
}
后序非递归:
void node::LRD()
{
deque<node*> s; // use deque as stack
s.push(this);
while(!s.empty())
{
node* tp = s.top();
if(tp == NULL)
{
s.pop();
continue;
}
if(tp->visited == 0)
{
tp->visited += 1;
s.push(tp->lchild);
}
else if(tp->visited == 1)
{
tp->visited += 1;
s.push(tp->rchild);
}
else if(tp->visited == 2)
{
cout<<tp->data;
s.pop();
}
}
}
二叉树结构实现
class node
{
public:
node();
node* lchild; // 左孩子
node* rchild; // 右孩子
char data; // 数据域
// 清除visited标志,递归
void dfs_clear_visit(node* &t);
int visited; // 第几次被访问?
void DLR(); // 先序非递归
void LDR(); // 中序非递归
void LRD(); // 后序非递归
};
node::node()
{
this->lchild = NULL;
this->rchild = NULL;
this->visited = 0;
}
创建二叉树(递归)
#define null_char '#'
void creatTree(node* &t)
{
char c;
cin>>c;
if(c != null_char)
{
node* nd = new node();
nd->data = c;
t = nd;
creatTree(t->lchild);
creatTree(t->rchild);
}
}
递归地清除visited访问标志
void node::dfs_clear_visit(node* &t)
{
if(t != NULL)
{
t->visited = 0;
dfs_clear_visit(t->lchild);
dfs_clear_visit(t->rchild);
}
}
完整代码:
#include <iostream>
#include <deque>
using namespace std;
class node
{
public:
node();
node* lchild; // 左孩子
node* rchild; // 右孩子
char data; // 数据域
// 清楚visited标志,递归
void dfs_clear_visit(node* &t);
int visited; // 第几次被访问?
void DLR(); // 先序非递归
void LDR(); // 中序非递归
void LRD(); // 后序非递归
};
node::node()
{
this->lchild = NULL;
this->rchild = NULL;
this->visited = 0;
}
void node::dfs_clear_visit(node* &t)
{
if(t != NULL)
{
t->visited = 0;
dfs_clear_visit(t->lchild);
dfs_clear_visit(t->rchild);
}
}
#define null_char '#'
void creatTree(node* &t)
{
char c;
cin>>c;
if(c != null_char)
{
node* nd = new node();
nd->data = c;
t = nd;
creatTree(t->lchild);
creatTree(t->rchild);
}
}
#define push push_back
#define pop pop_back
#define top back
void node::DLR()
{
deque<node*> s; // use deque as stack
s.push(this);
while(!s.empty())
{
node* tp = s.top();
if(tp == NULL)
{
s.pop();
continue;
}
if(tp->visited == 0)
{
cout<<tp->data;
tp->visited += 1;
s.push(tp->lchild);
}
else if(tp->visited == 1)
{
tp->visited += 1;
s.push(tp->rchild);
}
else if(tp->visited == 2)
{
s.pop();
}
}
}
void node::LDR()
{
deque<node*> s; // use deque as stack
s.push(this);
while(!s.empty())
{
node* tp = s.top();
if(tp == NULL)
{
s.pop();
continue;
}
if(tp->visited == 0)
{
tp->visited += 1;
s.push(tp->lchild);
}
else if(tp->visited == 1)
{
cout<<tp->data;
tp->visited += 1;
s.push(tp->rchild);
}
else if(tp->visited == 2)
{
s.pop();
}
}
}
void node::LRD()
{
deque<node*> s; // use deque as stack
s.push(this);
while(!s.empty())
{
node* tp = s.top();
if(tp == NULL)
{
s.pop();
continue;
}
if(tp->visited == 0)
{
tp->visited += 1;
s.push(tp->lchild);
}
else if(tp->visited == 1)
{
tp->visited += 1;
s.push(tp->rchild);
}
else if(tp->visited == 2)
{
cout<<tp->data;
s.pop();
}
}
}
int main()
{
int n;
cin>>n;
while(n--)
{
node* t = new node();
creatTree(t);
t->dfs_clear_visit(t);
t->DLR();
cout<<endl;
t->dfs_clear_visit(t);
t->LDR();
cout<<endl;
t->dfs_clear_visit(t);
t->LRD();
cout<<endl;
}
return 0;
}