1、前序遍历
用栈来实现二叉树非递归的先序遍历,先序遍历的方式是根->左->右,按照栈的入站退栈方式,应该先入根节点然后根节点退出再入右孩子和左孩子,只要栈不为空证明还没有遍历完二叉树。
void PreOrder(BtNode *root)
{
stack<BtNode*>s; //生成一个栈
if (root != NULL) //如果传的root节点不为空,则将root入栈
{
s.push(root);
}
while (!s.empty()) //只要栈里还有节点
{
BtNode*top = s.top(); //保存一下栈顶节点
s.pop(); //栈顶节点退栈
cout << top->data << " "; //打印出刚才的数据
if (top->rightchild) //右孩子存在就入栈
{
s.push(top->rightchild);
}
if (top->leftchild) //左孩子存在就入栈
{
s.push(top->leftchild);
}
}
cout << endl;
}
2、中序遍历
用栈来实现二叉树非递归的中序遍历,先序遍历的方式是左->根->右。
入栈:用一个指针从root开始遍历左孩子并入栈。
将栈顶元素输出再出栈(每次出栈的栈顶元素都是左孩子已经遍历或者没有左孩子),再把右孩子赋值给该指针,遍历右边的元素。
void InOrder(BtNode *p)
{
stack<BtNode*>s;
BtNode* cur = p;
while(cur != NULL || !s.empty ())
{
while(cur != NULL)
{
s.push(cur);
cur = cur->leftchild ;
}
BtNode* top = s.top ();
s.pop();
cout<<top->data<<" ";
if(top->rightchild != NULL)
{
cur = top->rightchild;
}
}
cout<<endl;
}
3、后序遍历
用栈来实现二叉树非递归的中序遍历,先序遍历的方式是左->右->根。
由于我们的访问只能从上到下,所以要多定义一个指针来保存已经被输出的节点,避免访问不到右孩子。
void PastOrder2(BtNode *p)
{
BtNode* cur = p;
BtNode* aftercur = p;
stack<BtNode*>s;
while(cur!=NULL || !s.empty() )
{
while(cur!=NULL)
{
s.push (cur );
cur = cur->leftchild ;
}
BtNode*top = s.top();
if(top->rightchild == NULL || aftercur == top->rightchild )
// 如果当前的top右孩子为NULL或者top是右孩子证明已经被遍历过,可以输出top了
{
s.pop();
cout<<top->data<<" ";
aftercur = top;
}
else
cur = top->rightchild;
}
cout<<endl;
}
总结:普通的二叉树都是从根节点开始向下遍历,访问到左边之后得退回到根节点再访问右边。所以:
前序遍历:根->左->右 先入栈出栈根节点,然后打印。再从上到下右孩子入栈,左孩子入栈。当左边不能进行了,打印栈顶元素,然后查看右边。
中序遍历:左->根->右 先入栈根节点,然后自顶向下入栈左孩子,直到不能入栈,打印当前节点,查看它是否有右孩子,如果有遍历右边。
后续遍历:左->右->根 先入栈根节点,然后自顶向下入栈左孩子,直到不能入栈,打印当前节点, 查看它是否有右孩子,如果有遍历右边。只有没有右孩子或者当前的栈顶元素为右孩子(证明已经访问过右孩子)才能输出根。