二叉树的遍历是二叉树的众多算法的基础。主要有,前序,中序与后序。
对于以下二叉树:
前序:12354
中序:21543
后序:24531
笔者实现了三种遍历方式:
1 前序:递归版本比较简单,只需要改变push_back操作的位置即可。
vector<int> PreOrderTraverse2(TreeNode *root)
{
vector<int> nodes;
vector<int> temp;
if(root == NULL) return nodes;
nodes.push_back(root->val);
temp = PreOrderTraverse2(root->left);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
temp = PreOrderTraverse2(root->right);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
return nodes;
}前序迭代版本,步骤如下:
(1)首先访问根节点root,先将root节点输出,压入堆栈,
(2)再考虑root节点的左子树,左子树也是一颗二叉树,重复(1)。
(3)某一步的左子树为空,那么该节点左子树已访问完毕,弹出栈顶,访问该节点的右子树,重复(1)即可。
很简单,只需要记住,在将节点压入堆栈时,该节点就已被访问,再访问完左孩子之后,再考虑右孩子所在的二叉树。
vector<int> PreOrderTraverse(TreeNode *root)
{
vector<int> nodes;
stack<TreeNode *> s;
if(root == NULL) return nodes;
TreeNode *temp = root;
while(temp || !s.empty())
{
while(temp)
{
s.push(temp);//入栈之前就访问
nodes.push_back(temp->val);
temp = temp->left;
}//左子树访问完毕
temp = s.top();
s.pop();
temp = temp->right;
}
return nodes;
}2 中序, 递归版本:
vector<int> InOrderTraverse2(TreeNode *root)
{
vector<int> nodes;
vector<int> temp;
if(root == NULL) return nodes;
temp = InOrderTraverse2(root->left);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
nodes.push_back(root->val);
temp = InOrderTraverse2(root->right);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
return nodes;
}迭代版本:
(1)首先访问根节点root,压入堆栈。
(2)访问root的左子树,重复(1)即可。
(3)如果某节点左子树为空,那么该节点输出,并考察其右子树,重复(1)即可。
PS:节点入栈使不访问,遇到节点就入栈,直到栈顶左子树访问完毕,那么将栈顶弹出,考虑右子树,重复即可。
vector<int> InOrderTraverse(TreeNode *root)
{
vector<int> nodes;
if(root == NULL) return nodes;
TreeNode *temp = root;
stack<TreeNode *> s;
while(temp || !s.empty())
{
while(temp)
{
s.push(temp);
temp = temp->left;
}// 左子树完毕
temp = s.top();
nodes.push_back(temp->val);
s.pop();
temp = temp->right;
}
return nodes;
}3 后序,递归版本:
vector<int> PostOrderTraverse2(TreeNode *root)
{
vector<int> nodes;
vector<int> temp;
if(root == NULL) return nodes;
temp = PostOrderTraverse2(root->left);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
temp = PostOrderTraverse2(root->right);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
nodes.push_back(root->val);
return nodes;
}迭代版本:步骤如下:
PS:遇到根节点root,分两种情况讨论,如果根节点的右子树还没被访问,那么根节点入栈;否则输出根节点。
vector<int> PostOrderTraverse(TreeNode *root)
{
vector<int> nodes;
if(root == NULL) return nodes;
TreeNode *temp = root;
TreeNode *pre = root; //记录前一次访问的节点
stack<TreeNode *> s;
while(temp || !s.empty())
{
while(temp)
{
s.push(temp);
temp = temp->left;
}
temp = s.top();
if (temp->right == NULL || pre == temp->right)
{
nodes.push_back(temp->val);
pre = temp;
s.pop();
temp = NULL;//保证不重复访问
}
else
{
temp = temp->right;
}
}
return nodes;
}后序遍历的递归版本比较复杂。自己在编写代码时会出现死循环,因为出现了重复访问,因此上述的temp=NULL语句很重要。
后记:上述3种算法的空间复杂度均为O(n)。
完整的代码为:
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x):val(x),left(NULL),right(NULL){}
};
vector<int> InOrderTraverse2(TreeNode *root)
{
vector<int> nodes;
vector<int> temp;
if(root == NULL) return nodes;
temp = InOrderTraverse2(root->left);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
nodes.push_back(root->val);
temp = InOrderTraverse2(root->right);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
return nodes;
}
vector<int> PreOrderTraverse2(TreeNode *root)
{
vector<int> nodes;
vector<int> temp;
if(root == NULL) return nodes;
nodes.push_back(root->val);
temp = PreOrderTraverse2(root->left);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
temp = PreOrderTraverse2(root->right);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
return nodes;
}
vector<int> PostOrderTraverse2(TreeNode *root)
{
vector<int> nodes;
vector<int> temp;
if(root == NULL) return nodes;
temp = PostOrderTraverse2(root->left);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
temp = PostOrderTraverse2(root->right);
for(vector<int>::size_type i = 0 ; i != temp.size() ; ++i)
nodes.push_back(temp[i]);
nodes.push_back(root->val);
return nodes;
}
vector<int> PreOrderTraverse(TreeNode *root)
{
vector<int> nodes;
stack<TreeNode *> s;
if(root == NULL) return nodes;
TreeNode *temp = root;
while(temp || !s.empty())
{
while(temp)
{
s.push(temp);//入栈之前就访问
nodes.push_back(temp->val);
temp = temp->left;
}
temp = s.top();
s.pop();
temp = temp->right;
}
return nodes;
}
vector<int> InOrderTraverse(TreeNode *root)
{
vector<int> nodes;
if(root == NULL) return nodes;
TreeNode *temp = root;
stack<TreeNode *> s;
while(temp || !s.empty())
{
while(temp)
{
s.push(temp);
temp = temp->left;
}
temp = s.top();
nodes.push_back(temp->val);
s.pop();
temp = temp->right;
}
return nodes;
}
vector<int> PostOrderTraverse(TreeNode *root)
{
vector<int> nodes;
if(root == NULL) return nodes;
TreeNode *temp = root;
TreeNode *pre = root; //记录前一次访问的节点
stack<TreeNode *> s;
while(temp || !s.empty())
{
while(temp)
{
s.push(temp);
temp = temp->left;
}
temp = s.top();
if (temp->right == NULL || pre == temp->right)
{
nodes.push_back(temp->val);
pre = temp;
s.pop();
temp = NULL;//保证不重复访问
}
else
{
temp = temp->right;
}
}
return nodes;
}
int main()
{
vector<int> nodes;
TreeNode *root = new TreeNode(1);
TreeNode *node2 = new TreeNode(2);
TreeNode *node3 = new TreeNode(3);
TreeNode *node4 = new TreeNode(4);
TreeNode *node5 = new TreeNode(5);
root->left = node2;
root->right = node3;
node5->right = node4;
node3->left = node5;
cout << "InOrder recursively..." << endl;
nodes = InOrderTraverse2(root);
for(vector<int>::size_type i = 0; i != nodes.size(); i++)
cout << nodes[i] << " ";
cout << endl;
cout << "InOrder iterativelly..." << endl;
nodes = InOrderTraverse(root);
for(vector<int>::size_type i = 0; i != nodes.size(); i++)
cout << nodes[i] << " ";
cout << endl;
cout << "PreOrder recursively..." << endl;
nodes = PreOrderTraverse2(root);
for(vector<int>::size_type i = 0; i != nodes.size(); i++)
cout << nodes[i] << " ";
cout << endl;
cout << "PreOrder iterativelly..." << endl;
nodes = PreOrderTraverse(root);
for(vector<int>::size_type i = 0; i != nodes.size(); i++)
cout << nodes[i] << " ";
cout << endl;
cout << "PostOrder recursively..." << endl;
nodes = PostOrderTraverse2(root);
for(vector<int>::size_type i = 0; i != nodes.size(); i++)
cout << nodes[i] << " ";
cout << endl;
cout << "PostOrder iterativelly..." << endl;
nodes = PostOrderTraverse(root);
for(vector<int>::size_type i = 0; i != nodes.size(); i++)
cout << nodes[i] << " ";
cout << endl;
}
本文介绍了二叉树的前序、中序和后序遍历。前序遍历先访问根节点,再考虑左右子树;中序遍历从左子树开始,再访问根节点,最后处理右子树;后序遍历则先遍历左右子树,最后访问根节点。递归和非递归版本的算法思路也一并给出,强调了在遍历过程中何时访问节点和何时考虑子树。所有算法的空间复杂度都是O(n)。
1630

被折叠的 条评论
为什么被折叠?



