非递归的遍历需要使用栈保存当前不输出的结点,并且三种遍历顺序步骤有所不同。
中序遍历
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");
}