非递归的遍历需要使用栈保存当前不输出的结点,并且三种遍历顺序步骤有所不同。
中序遍历
1.查看其当前结点是否为空:
若非空则将当前结点入栈,指针指向其左孩子;
若当前结点为空,说明上一个入栈的结点没有左孩子,将上一个结点出栈打印;
2.之后指针指向其右孩子
3.循环步骤1、2,直到栈为空(所有结点都遍历完出栈了)
void NiceInOrder(BTNode*p)
{
if (p == NULL)return;
stack<BTNode*>st;
while (!st.empty()||p!=NULL)
{
while (p != NULL)
{
st.push(p);
p = p->lchild;
}
p = st.top();st.pop();
printf("%c ", p->data);
p = p->rchild;
}
printf("\n");
}
后序遍历
后序遍历因为先输出左右子树再输出根(14行),这个过程中需要通过根结点,所以需要有一个值来记录该根结点的左右子树是否都已经遍历(5行)。
要注意打印之后指针要指向空(19行),若当前树是某棵树的左子树,下次循环时为空则不在遍历这棵树了,否则程序陷入死循环。
void NicePastOrder(BTNode* p)
{
if (p == NULL)return;
stack<BTNode*>st;
BTNode* tag = NULL;//标记,指向遍历完右孩子的结点
while (!st.empty() || p != NULL)
{
while (p != NULL)//遍历左子树
{
st.push(p);
p = p->lchild;
}
p = st.top();
if (p->rchild == NULL || p->rchild == tag)//右子树为空或遍历完,打印根
{
st.pop();
printf("%c ", p->data);
tag = p;//指向遍历完的根
p = NULL;//表示左孩子已经遍历完了
}
else//否则指向右子树继续遍历
{
p = p->rchild;
}
}
printf("\n");
}
先序遍历
先序遍历是根左右的顺序,先入根结点,出根;
之后入栈顶的右、左孩子(因为栈先进后出,所以要先入右孩子)
void NicePreOrder(BTNode* p)
{
if (p == NULL)return;
stack<BTNode*>st;
st.push(p);
while (!st.empty())
{
p = st.top();
printf("%c ",p->data);
st.pop();
//先右后左入栈,先左后右出栈
if (p->rchild != NULL)
{
st.push(p->rchild);
}
if (p->lchild != NULL)
{
st.push(p->lchild);
}
}
}
层次遍历
层次遍历需要使用队列
步骤:
1.入根结点及其左右孩子;
2.出队头元素,入队头结点的左右孩子(不为空)
3.若队列为空则遍历完该树

void LevelOrder(BTNode* p)
{
if (p == NULL)return;
queue<BTNode*>qu;
qu.push(p);
while (!qu.empty())
{
p = qu.front();
printf("%c ",p->data);
qu.pop();
if(p->lchild!=NULL)
qu.push(p->lchild);
if (p->rchild != NULL)
qu.push(p->rchild);
}
printf("\n");
}
另一种非递归遍历要将每个结点出栈的次数记下:定义一个结构体
struct StkNode
{
BTNode* pnode;
int popnum;//出栈次数
};

后序遍历:每个结点都需要三次出栈,访问完它的左右根和自己
结点第一次入栈时出栈次数为0
当栈不为空,栈顶元素出栈
若出栈时popnum==3(第三次出栈,说明左右子树都遍历了),输出该结点;
若出栈时popnum==1且其左孩子不为空,则再将其入栈,并入其左孩子。
若出栈时popnum==2且其右孩子不为空,则再将其入栈,并入其右孩子;
void NicePastOrder_2(BTNode* p)
{
if (p = NULL)return;
stack<StkNode>st;
st.push(StkNode{ p,0 });
while (!st.empty())
{
StkNode node = st.top(); st.pop();
if (++node.popnum == 3)//左右子树都访问了
{
printf("%c ", node.pnode->data);
}
else
{
st.push(node);
if (node.popnum == 1 &&p->lchild!=NULL)
{
st.push(StkNode{node.pnode->lchild,0});
}
else if (node.popnum == 2 && p->rchild != NULL)
{
st.push(StkNode{ node.pnode->rchild,0 });
}
}
}
printf("\n");
}
中序遍历将顺序改一下,前序遍历就不需要这样了,第一种方法比较方便。