二叉树的非递归遍历方法
当二叉树的数据量小的时候,使用递归的方法遍历没有任何问题,但是在递归调用的时候会一层一层的建立函数调用的栈帧结构,计算机的栈空间是有限度的,若是数据量太大的时候,就容易在建立栈真结构的时候造成栈溢出而导致程序崩溃,将递归算法改为循环就可以解决这个问题。
非递归前序遍历:
如上图,在使用循环实现二叉树的非递归前序遍历的时候需要使用到栈数据结构stack。
创建一个栈stack 《Node *》 s (英文格式导致后面内容无法显示),从二叉树的根节点开始,先访问根节点,再将根节点的指针放入栈中,在访问其左根,再入栈……当遇到叶子结点时说明最小的一颗左子树已经遍历完成,将这个节点此时位于站顶,将它从栈中pop出去,记录下它的根节点的指针位置再pop出去(节点从栈中拿出来就表示其左子树已经访问完毕,只剩下右子树,有字数的访问逻辑与左子树相同,则看为子问题,用循环可以解决),访问这个根节点的右根……如图,栈 s 中的数字为每个数据的出入栈的顺序。
具体实现代码如下:
void PrevOrderNonR()//非递归前序遍历,用栈实现
{
stack<Node*> s;
Node* cur = _root;
while (cur || !s.empty())
{
while (cur)
{
cout << cur->_data << " ";
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();
s.pop();
cur = top->_right;
}
cout << endl;
}
非递归中序遍历:
非递归实现二叉树的中序遍历其逻辑与前序遍历相同,唯一不同的就是前序遍历是先访问再入栈,而中序遍历只需要将这两个的顺序改变为先入栈,等出栈是再行访问即可。
具体实现如下:
void InOrderNonR()//非递归中序遍历,用栈实现
{
stack<Node*> s;
Node* cur = _root;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();
s.pop();
cout << top->_data << " ";
cur = top->_right;
}
cout << endl;
}
非递归后序遍历:
非递归的后序遍历则有点不同,还是先从根节点入栈,再一直走左子树的根节点入栈,到叶子结点入栈之后就可以将其取出访问,再pop掉,此时栈顶会退回到那个叶子结点的根节点,这个节点已经入栈,则走它的右子树入栈,当再次回退到这里时才可以访问这个节点,但是无法识别到底是从左子树回退的还是从右子树回退的(如图中的步骤4和6)。所以在这里需要一个特殊的指针来判断哪里回退的,从左子树回退的就不用处理,从右子树回退的则表示其左右子树都访问完毕,则需要访问此节点。
具体实现如下:
void IPostOrderNonR()//非递归后序遍历,用栈实现
{
Node* cur = _root;
stack<Node*> s;
Node* prev = NULL;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
Node* front = s.top();
if (NULL == front->_right || prev == front->_right)
{
cout << front->_data << " ";
prev = front;
s.pop();
}
else
{
cur = front->_right;
}
}
cout << endl;
}