非递归遍历树算法以前我一直死记书本的用栈保存,最近笔试时要求写非递归遍历,想了很久都没有写好。回家后,我回顾重新学习了这个非递归遍历算法,总结了一下于是写下来记下。
其实遍历每个节点的过程中,有三种状态是必须记录下的,1、没访问左子树。2、已访问左子树。3、没访问右子树。每种状态须要执行的操作分别是,1、左孩子节点入栈,2、访问结点信息(中序遍历),3、右孩子节点入栈。其中已访问左子树,由下图的虚线表示,并且此时进行访问节点信息和弹栈操作。
非递归遍历算法,状态2的表示是关键,这个可以通过检测其是不是NULL节点返回来判断。
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<stack>
#include<algorithm>
using namespace std;
struct Node{
int value;
Node *L, *R;
};
#define MemNode(nd) nd=(Node*)malloc(sizeof(*nd))
void CreateTree(Node *&root){
MemNode(root);
root->value = 1;
MemNode(root->L);
MemNode(root->R);
Node *L = root->L;
Node *R = root->R;
R->value = 4;
R->L = R->R = NULL;
L->value = 2;
L->L = NULL;
MemNode(L->R);
L->R->value = 3;
L->R->L = L->R->R = NULL;
}
int dfs(Node *p){
if (p->L == NULL && p->R == NULL) {
printf("%d\n",p->value);
return p->value;
}
int lv = 0, rv = 0;
if (p->L) lv = dfs(p->L);
printf("%d\n", p->value);
if (p->R) rv = dfs(p->R);
return lv + rv + p->value;
}
void visit(Node *p,int &sum){
sum += p->value;
printf("%d\n",p->value);
}
int traverse(Node *p){
stack<Node*> stTree;
stTree.push(p);
int sum = 0;
while (!stTree.empty()){
Node *nd = stTree.top();
if (nd != NULL){
stTree.push(nd->L);
}else{
stTree.pop();
if (!stTree.empty()){
Node *tp = stTree.top(); stTree.pop();
visit(tp, sum);
stTree.push(tp->R);
}
}
}
return sum;
}
int main(){
Node *root = NULL;
CreateTree(root);
int dfsTot = dfs(root);
printf("sum = %d\n",dfsTot);
printf("=================================================================");
puts("\nNon-recursive Traverse");
int traTot = traverse(root);
printf("sum = %d\n",traTot);
return 0;
}
上面代码CreateTree是创建如图所示结构的树,dfs使用递归遍历树并求和,traverse使用了非递归算法。