非递归遍历二叉树的基本思想是使用堆栈组织输出顺序,使用pair记录节点的左和右子树是否被遍历过。
如何使用堆栈组织输出顺序?以后序遍历为例,后序遍历中最后输出父节点,也就是先将根节点入栈,再将右节点入栈,最后将左节点压入栈。这样在下一轮中,从堆栈中pop出的节点就是左节点,左节点的左节点和右节点还未被遍历,因此会进入下一轮同样的入栈....直到节点的左和右都是NULL,如果都是NULL,栈顶被pop出后就丢弃了,那么下一个被pop出的就是父节点,父节点被pop出后下一个就是父节点的兄弟节点...以此类推。
根据上述思想,只需要以合适的顺序将父、左、右节点入栈即可,注意,父节点入栈时要将其标记为已经被遍历过,也就是,在轮到一个父节点被pop时,它一定是准备好了被打印的。
void preorderTraversalNew(TreeNode *root, vector<int> &path)
{
stack< pair<TreeNode *, bool> > s;
s.push(make_pair(root, false));
bool visited;
while(!s.empty())
{
root = s.top().first;
visited = s.top().second;
s.pop();
if(root == NULL)
continue;
if(visited)
{
path.push_back(root->val);
}
else
{
s.push(make_pair(root->right, false));
s.push(make_pair(root->left, false));
s.push(make_pair(root, true));
}
}
}
//更简单的非递归中序遍历
void inorderTraversalNew(TreeNode *root, vector<int> &path)
{
stack< pair<TreeNode *, bool> > s;
s.push(make_pair(root, false));
bool visited;
while(!s.empty())
{
root = s.top().first;
visited = s.top().second;
s.pop();
if(root == NULL)
continue;
if(visited)
{
path.push_back(root->val);
}
else
{
s.push(make_pair(root->right, false));
s.push(make_pair(root, true));
s.push(make_pair(root->left, false));
}
}
}
//更简单的非递归后序遍历
void postorderTraversalNew(TreeNode *root, vector<int> &path)
{
stack< pair<TreeNode *, bool> > s;
s.push(make_pair(root, false));
bool visited;
while(!s.empty())
{
root = s.top().first;
visited = s.top().second;
s.pop();
if(root == NULL)
continue;
if(visited)
{
path.push_back(root->val);
}
else
{
s.push(make_pair(root, true));
s.push(make_pair(root->right, false));
s.push(make_pair(root->left, false));
}
}
}