既然做了这道题,也就顺便复习一下二叉树的遍历方法吧。
注:这里默认已经实现了栈和队列等结构,就直接调用了。
1.前序遍历
先自身,后左子树,最后右子树。
递归:
void PreOrder(TreeNode *root)
{
if (root==NULL)
return ;
Execute(root);
PreOrder(root->left);
PreOrder(root->right);
}
非递归(用到了栈):
void PreOrder(TreeNode *root)
{
stack S;
while(root||!S.empty())
{
if (root)
{
Execute(root);
S.push(root);
root=root->left;
}
else
{
root=S.top();
S.pop();
root=root->right;
}
}
}
2.中序遍历
先左子树,后自己,最后右子树。
递归:
void InOrder(TreeNode *root)
{
if (!root)
return ;
InOrder(root->left);
Execute(root);
InOrder(root->right);
}
非递归:
void InOrder(TreeNode *root)
{
stack s;
while(root||!s.empty())
{
if (root)
{
s.push(root);
root=root->left;
}
else
{
root=s.top();
s.pop();
Execute(root);
root=root->right;
}
}
}
3.后序遍历
先左子树,后右子树,最后自己。
递归:
void PostOrder(TreeNode *root)
{
if (!root)
return ;
PostOrder(root->left);
PostOrder(root->right);
Execute(root);
}
后序遍历的非递归要稍微麻烦一些,需要使用一个标记位来标识该节点是否被访问过。
算法如下:
1. 如果根节点非空,入栈;否则结束。
2. 如果栈非空,取栈顶节点(但不pop);否则结束程序。
3. 若该节点满足以下任意一个条件,输出,并从栈中pop,跳到第二步,否则继续下一步
* 该节点为叶子节点;
* 上一个访问的是它的子结点
4. 如果右节点非空,入栈;
5. 如果左节点非空,入栈;
6. 跳到第2步。
void PostOrder(TreeNode* root)
{
if(root==NULL)
return ;
stack s;
TreeNode *Current;
TreeNode *Pre=NULL;
s.push(root);
while (!s.empty())
{
Current = s.top();
if ((Current->left == NULL && Current->right== NULL) || (Pre != NULL && (Pre == Current->left || Pre == Current->right)))
{
Execute(Current);
s.pop();
Pre = Current;
}
else
{
if (Current->right != NULL)
{
s.push(Current->right);
}
if (Current->left != NULL)
{
s.push(Current->left);
}
}
}
}
还有一种算法,使用两个栈巧妙的得到了后序遍历序列。
算法如下
1.如果根节点非空,入栈s;否则结束程序;
2.如果栈s非空,从栈s中pop一个节点;否则结束程序;
3.将该节点的左节点压入栈中(如果存在);
4.将该节点的右节点压入栈中(如果存在);
5.将该节点压入第二个栈f,跳到第2步。
void PostOrder(TreeNode *root)
{
if (!root)
return ;
stack s;
stack f;
s.push(root);
while(!s.empty())
{
root=s.top();
s.pop();
if (root->left)
s.push(root->left);
if (root->right)
s.push(root->right);
f.push(root);
}
while(!f.empty())
{
root=f.top();
f.pop();
Execute(root);
}
}
Morris方法
最近了解到了一种O(1)空间的二叉树遍历方法,Morris方法,懒得说了,上链接。