遍历顺序不同其实就是根节点所在的位置不同
1.前序遍历:根节点--->根节点的左子树--->根节点的右子树
2.中序遍历:根节点的左子树--->根节点--->根节点的右子树
3.后序遍历:根节点的左子树--->根节点的右子树--->根节点
递归
----------
//前序
void PreOrder(BTNode* Root)
{
if(Root)
{
printf("%c ",Root->data);
PreOrder(Root->Left);
PreOrder(Root->Right);
}
}
//中序
void InOrder(BTNode* Root)
{
if(Root)
{
InOrder(Root->Left);
printf("%c ",Root->data);
InOrder(Root->Right);
}
}
//后序
void PostOrder(BTNode* Root)
{
if(Root)
{
PostOrder(Root->Left);
PostOrder(Root->Right);
printf("%c ",Root->data);
}
非递归(循环)
循环方法遍历借助 栈 ,压入 或 弹出数据.
前序遍历,先遍历根节点,所以把根节点压栈,此时栈不为空,
则进入while 循环,遍历栈顶元素,则Pop语句先把根节点拿了出来。
因为在栈里,是后进先出,所以把先要遍历的左子树,左孩子放在第二个
if 语句中,则在遍历过程中,随着栈顶元素的改变,最后按照原则得到结果。
当栈为空时,循环结束,则遍历结束。
//前序
void PreOrderNor(BTNode* Root)
{
Stack s;
BTNode* cur;
if(Root == NULL)
return ;
StackInit(&s);
StackPush(&s,Root);
while(!StackEmpty(&s))
{
cur = StackTop(&s);
printf("%c ",cur->data);
StackPop(&s);
if(cur->Right)
{
StackPush(&s,cur->Right);
}
if(cur->Left)
{
StackPush(&s,cur->Left);
}
}
}
中序遍历先找到cur为根的最左侧的节点,并保存所经路径中所有的节点
然后遍历右子树
void InOrderNor(BTNode* Root)
{
Stack s;
BTNode* cur = Root;
if(Root == NULL)
return ;
StackInit(&s);
while(!StackEmpty(&s)||(cur))
{
//找以cur为根的二叉树的最左侧的节点,并保存所经过的路径中的所有节点
while(cur)
{
StackPush(&s,cur);
cur = cur->Left;
}
cur = StackTop(&s);
printf("%c ",cur->data);
StackPop(&s);
//遍历以cur为根的右子树
cur = cur->Right;
}
}
ret用来避免已经遍历过的节点再次被遍历
void PostOrderNor(BTNode* Root)
{
Stack s;
BTNode* cur = Root;
BTNode* del;
BTNode* ret; //标记最近访问过的节点
if(Root == NULL)
return ;
StackInit(&s);
while(!StackEmpty(&s)||(cur))
{
//找以cur为根的二叉树的最左侧的节点,并保存所经过的路径中的所有节点
while(cur)
{
StackPush(&s,cur);
cur = cur->Left;
}
del = StackTop(&s);
//del为根的二叉树的根节点不能直接遍历
//除非:del的右子树为空 或者 del的右子树已经遍历
if(del->Right == NULL || ret == del->Right)
{
printf("%c ",del->data);
ret = del;
StackPop(&s);
}
else
{
cur = del->Right;
}
}
}