前言
学过二叉树的同学一定对二叉树的三种遍历方式印象深刻。前序遍历,中序遍历,后序遍历,用递归来实现不仅代码简单而且结构优美,而且令人心情舒畅。那么假如我们不用递归,用循环来实现又如何呢?一起来看看。
结构体
这里定义最简单的树结构
struct Tree{
int val;
Tree* left;
Tree* right;
};
前序遍历
先看看递归实现,很简单的
//前序遍历
void PrintfTree(Tree* node){
if(node!=NULL){
printf("%d ",node->val);
PrintfTree(node->left);
PrintfTree(node->right);
}
}
如果不用递归,我们需要借组栈来实现:
//前序遍历非递归遍历
void PrintfTree(Tree* head){
Tree* p=head;
stack<Tree*> s;//没学过stack的朋友可自行搜索用法
while (p!=NULL||!s.empty()) {
//先往left节点查找,直到节点为NULL停止,同时将遇到的每个节点都压入栈中
//压入栈的节点在后面还要查找其right节点
if (p!=NULL) {
//前序遍历的特点,先遇到的节点先输出
printf("%d ",p->val);
s.push(p);
p=p->left;
}else{
//left节点都搜索完了,转向right节点
p=s.top()->right;
s.pop();
}
}
}
其实也不难嘛,对吧。
中序遍历
递归实现
//中序遍历
void PrintfTree(Tree* node){
if(node!=NULL){
PrintfTree(node->left);
printf("%d ",node->val);
PrintfTree(node->right);
}
}
循环实现,中序遍历和前序遍历很像,来看看:
//中序遍历非递归遍历
void PrintfTree(Tree* head){
Tree* p=head;
stack<Tree*> s;
while (p!=NULL||!s.empty()) {
//先往left节点搜索,直到节点为NULL停止,同时将遇到的每个节点都压入栈中
//压入栈的节点在后面还要查找其right节点
if (p!=NULL) {
s.push(p);
p=p->left;
}else{
//中序遍历,也就是这里和前序遍历不一致
//此时是栈顶的值先输出
printf("%d ",s.top()->val);
//left节点都搜索完了,转向right节点
p=s.top()->right;
s.pop();
}
}
}
后序遍历
递归实现
//后序遍历
void PrintfTree(Tree* node){
if(node!=NULL){
PrintfTree(node->left);
PrintfTree(node->right);
printf("%d ",node->val);
}
}
后序遍历有点不太一样,要稍微难一点:
//后序遍历
void PrintfTree2(struct Tree* head){
struct Tree* p=head;
stack<Tree*> s;
stack<bool> u;//加标志位,false代表未遍历,true代表已遍历
while (p!=NULL||!s.empty()) {
if(p!=NULL){
s.push(p);
u.push(false);
//先搜索左子节点
p=p->left;
}else{
//判断是否有右子节点,且该节点是否已遍历。
//是则搜索右节点,把当前节点标志设置为已遍历
//否则打印数值并从栈中删除
if(s.top()->right!=NULL&&!u.top()){
p=s.top()->right;
u.pop();
u.push(true);
}else{
printf("%d ",s.top()->val);
s.pop();
u.pop();
}
}
}
}
总结
前序遍历、中序遍历的实现还是比较容易理解的,不过后序遍历要稍微多绕一个弯。搞明白以后其实还是蛮简单的。代码作为参考,说的不清楚的地方,希望各位自己多思考或者直接在评论区提问。