前序遍历非递归:
每次都是走树的左子树,直到左子树为空,然后从递归的最深处返回到父节点,访问右节点。因此,这里需要一个方法来对节点序列来回溯。将访问途中遇到的节点都记录下来。
vector<char> preOrder1(TreeNode *root)
{
stack<TreeNode *> s;
vector<char> result;
TreeNode *p = root;
while(p!=NULL || !s.empty())
{
while(p!=NULL)
{
result.push_back(p->data);
s.push(p);//先序,先访问再入栈
p = p->left;//依此访问左子树
}
if(!s.empty())
{
p = s.top();//回溯到父节点
s.pop();
p = p->right;
}
}
return result;
}
中序遍历非递归:
和前序遍历的区别是,前序是先访问后入栈,这里是先入栈后访问。
vector<char> midOrder1(TreeNode *root)
{
stack<TreeNode *> s;
vector<char> result;
TreeNode *p = root;
while(p != NULL || !s.empty())
{
while(p!=NULL)
{
s.push(p);
p = p->left;
}
if(!s.empty())
{
p = s.top();
s.pop();
result.push_back(p->data);
p = p->right;
}
}
return result;
}
后续遍历非递归:
用栈来模拟递归的实现。三个节点都要入栈,顺序是root->right->left。入栈后,根节点和左右节点分不清楚,所以需要引进一个标志位bPushed,表示该节点左右子树都入栈了。
vector<char> postOrder1(TreeNode *root)
{
vector<char> result;
stack<TreeNode *> s;
if(root)
{
s.push(root);
root->bPushed = false;
}
while(!s.empty())
{
TreeNode *p = s.top();
s.pop();
if(p->bPushed)
{
result.push_back(p->data);
}
else
{
p->bPushed = true;
s.push(p);
if(p->right != NULL)
{
p->right->bPushed = false;
s.push(p->right);
}
if(p->left != NULL)
{
p->left->bPushed = false;
s.push(p->left);
}
}
}
return result;
}
二叉树遍历(递归和非递归方法)
下面的code实现了很多种遍历的方法,不仅仅是上面的。
参考了:http://blog.youkuaiyun.com/chencheng126/article/details/44020269
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
struct TreeNode
{
char data;
TreeNode *left;
TreeNode *right;
bool bPushed;//表示该节点的左右子树都入栈了
};
//前序遍历
//1.递归
void preOrder(TreeNode *root,vector<char> &result)
{
if(root)
{
result.push_back(root->data);
preOrder(root->left,result);
preOrder(root->right,result);
}
}
//栈1。
//思路一:仔细分析一下递归程序,可以发现每次都是走树的左子树,直到左子树为空,然后从递归的最深处返回到父节点,访问右节点。因此,这里需要一个方法来对节点序列来回溯。将访问途中遇到的节点都记录下来。因为节点出现的次序和恢复的顺序是相反的,因此要用到栈。
vector<char> preOrder1(TreeNode *root)
{
stack<TreeNode *> s;
vector<char> result;
TreeNode *p = root;
while(p!=NULL || !s.empty())
{
while(p!=NULL)
{
result.push_back(p->data);
s.push(p);//先序,先访问再入栈
p = p->left;//依此访问左子树
}
if(!s.empty())
{
p = s.top();//回溯到父节点
s.pop();
p = p->right;
}
}
return result;
}
//栈2
//思路二;用栈来模拟递归的实现。将root压栈,然后弹出,压右子树,然后压左子树。
vector<char> preOrder2(TreeNode *root)
{
vector<char> result;
stack<TreeNode *> s;
if(root)
{
s.push(root);
while(!s.empty())
{
TreeNode *p = s.top();
s.pop();
result.push_back(p->data);//访问root节点,不需要入栈
if(p->right)
s.push(p->right);
if(p->left)
s.push(p->left);
}
}
return result;
}
//中序遍历
//1.递归
void midOrder(TreeNode* root,vector<char> &result)
{
if(root)
{
midOrder(root->left,result);
result.push_back(root->data);
midOrder(root->right,result);
}
}
//栈实现方式。先序的第一种方法,是先访问再入栈,这里是先入栈,再访问。
vector<char> midOrder1(TreeNode *root)
{
stack<TreeNode *> s;
vector<char> result;
TreeNode *p = root;
while(p != NULL || !s.empty())
{
while(p!=NULL)
{
s.push(p);
p = p->left;
}
if(!s.empty())
{
p = s.top();
s.pop();
result.push_back(p->data);
p = p->right;
}
}
return result;
}
//用栈来模拟递归的实现。这个和preOrder2不同之处在于,preOrder的左右节点压栈之后,root节点就不用管了。而midOrder和postOrder在左右节点压栈后,root节点还是要访问,因此三个节点都要入栈。对于midOrder来说,压栈的顺序是right->root->left。但是入栈以后,根节点和左右子树节点区分不清楚,这就需要引进一个标志位,表示该节点的左右子树入栈了。
vector<char> midOrder2(TreeNode *root)
{
stack<TreeNode *> s;
vector<char> result;
if(root)
{
s.push(root);
root->bPushed = false;
}
while(!s.empty())
{
TreeNode *p = s.top();
s.pop();
if(p->bPushed)
{
result.push_back(p->data);
}
else
{
if(p->right != NULL)
{
p->right->bPushed = false;
s.push(p->right);
}
p->bPushed = true;
s.push(p);
if(p->left != NULL)
{
p->left->bPushed = false;
s.push(p->left);
}
}
}
return result;
}
//后序遍历
//递归
void postOrder(TreeNode *root,vector<char> &result)
{
if(root)
{
if(root->left)
postOrder(root->left,result);
if(root->right)
postOrder(root->right,result);
result.push_back(root->data);
}
}
//栈实现。模拟递归的实现,和midOrder2类似,不同之处是入栈的顺序变了,root->right->left.
vector<char> postOrder1(TreeNode *root)
{
vector<char> result;
stack<TreeNode *> s;
if(root)
{
s.push(root);
root->bPushed = false;
}
while(!s.empty())
{
TreeNode *p = s.top();
s.pop();
if(p->bPushed)
{
result.push_back(p->data);
}
else
{
p->bPushed = true;
s.push(p);
if(p->right != NULL)
{
p->right->bPushed = false;
s.push(p->right);
}
if(p->left != NULL)
{
p->left->bPushed = false;
s.push(p->left);
}
}
}
return result;
}
//根据前序和中序来创建二叉树
void makeBinaryTree1(TreeNode **root,char *preOrder,char *midOrder,int length)
{
if(length == 0)
{
(*root) = NULL;
return;
}
(*root) = new TreeNode;
(*root)->data = *preOrder;
char *rootplace = strchr(midOrder,(*root)->data);
if(rootplace == NULL)
{
printf("Wrong sample!");
}
int leftTreeLength = strlen(midOrder) - strlen(rootplace);
int rightTreeLength = length - leftTreeLength -1;
makeBinaryTree1(&(*root)->left,preOrder+1,midOrder,leftTreeLength);
makeBinaryTree1(&(*root)->right,preOrder+leftTreeLength+1,rootplace+1,rightTreeLength);
}
void main()
{
char pre[] = "abdeijcfg";
char mid[] = "dbiejafcg";
TreeNode* r;
makeBinaryTree1(&r,pre,mid,strlen(pre));
vector<char> result;
//preOrder(r,result);
//result = preOrder2(r);
//midOrder(r,result);
//result = midOrder2(r);
//postOrder(r,result);
result = postOrder1(r);
for(unsigned int i=0;i < result.size();i++)
{
cout<<result[i]<<endl;
}
return;
}