先序、中序和后序遍历过程:遍历过程中经过结点的路线一 样,只是访问各结点的时机不同。
1、递归实现
```cpp
#include <stdio.h>
#include <stdlib.h>
typedef char ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
BinTree CreatBinTree(); /* 实现细节忽略 */
void InorderTraversal( BinTree BT );
void PreorderTraversal( BinTree BT );
void PostorderTraversal( BinTree BT );
void LevelorderTraversal( BinTree BT );
int main()
{
BinTree BT = CreatBinTree();
printf("Inorder:"); InorderTraversal(BT); printf("\n");
printf("Preorder:"); PreorderTraversal(BT); printf("\n");
printf("Postorder:"); PostorderTraversal(BT); printf("\n");
printf("Levelorder:"); LevelorderTraversal(BT); printf("\n");
return 0;
}
/* 你的代码将被嵌在这里 */
void InorderTraversal( BinTree BT ){
if(BT){
InorderTraversal(BT->Left);
printf(" %c",BT->Data);
InorderTraversal(BT->Right);
}
}
void PreorderTraversal( BinTree BT ){
if(BT){
printf(" %c",BT->Data);
PreorderTraversal(BT->Left);
PreorderTraversal(BT->Right);
}
}
void PostorderTraversal( BinTree BT ){
if(BT){
PostorderTraversal(BT->Left);
PostorderTraversal(BT->Right);
printf(" %c",BT->Data);
}
}
void LevelorderTraversal( BinTree BT ){
BinTree que[100], temp;//que为元素类型为BinTree的数组,当作队列使用,temp用来暂存当前节点
int head=0,rear=0;//从队尾进队头出
if(BT){
que[rear++] = BT;
while(head-rear){//队非空时
temp = que[head++];//当前节点为队头节点
printf(" %c",temp->Data);
if(temp->Left) que[rear++] = temp->Left;
if(temp->Right) que[rear++] = temp->Right;
}
}
}
2、非递归实现:
使用堆栈
中序遍历非递归遍历算法
①遇到一个结点,就把它压栈,并去遍历它的左子树;
②当左子树遍历结束后,从栈顶弹出这个结点并访问它;
③然后按其右指针再去中序遍历该结点的右子树
难理解的是后序遍历:
1 借助堆栈实现前序遍历、中序遍历非递归程序的本质是利用堆栈模拟递归函数调用时的入栈和出栈过程。而前序遍历、中序遍历和后序遍历在递归函数执行时,结点(作为函数参数)的入栈和出栈过程是完全一样的。
2 前序遍历是在结点入栈时输出结点信息,然后开始分别对该结点左右子树的遍历;而在中序遍历中,结点出栈时表明刚完成对该结点左子树的遍历,此时可输出该结点信息。
3 后序遍历必须在左右子树均输出的情况下才能输出该结点。如果直接采用前序遍历、中序遍历的非递归程序,我们没法判别该结点的右子树什么时候遍历结束。为了能知道结点右子树什么时候遍历结束,可以在其左子树遍历结束(即该结点出栈)时,将该结点再次入栈,等到它再次出栈时就说明其右子树刚刚遍历完毕,此时可以输出该结点。
也就是在后序遍历的非递归过程中,可以让每个结点两次入出栈,第一次出栈说明其左子树已遍历完成,第二次出栈说明右子树也遍历完成,可以输出结点信息。为了区分到底是第几次入出栈,可以给每个入栈结点增加一个标记(也就需要采用结构,其中一个分量作为标记以区分第几次入出栈)。
void InorderTraversal(BinTree BT)
{
BinTree S[100];
BinTree T;
T=BT;
int top=-1;
while(T||top!=-1)
{
while(T)
{
S[++top]=T;
T=T->Left;
}
if(top!=-1)
{
T=S[top--];
printf(" %c",T->Data);//访问节点时机
T=T->Right;
}
}
}
void PreorderTraversal(BinTree BT)
{
BinTree S[100];
BinTree T;
T=BT;
int top=-1;
while(T||top!=-1)
{
while(T)
{
printf(" %c",T->Data);//访问节点时机
S[++top]=T;
T=T->Left;
}
if(top!=-1)
{
T=S[top--];
T=T->Right;
}
}
}
void PostorderTraversal( BinTree BT )//后序
{
/*左 右 根*/
BinTree T = BT;
Stack S = CreateStack();//创建堆栈
while (T || !IsEmpty(S))//当树不空或者堆栈不空时
{
while (T)//一直访问左子树
{
Push(S,T);//入栈
T->flag = 1;//第一次入栈
T = T->Left;
}
if (!IsEmpty(S))//左子树遍历完后
{
T = Pop(S);//出栈
if(T->flag == 1)//如果第一次入栈,右节点入栈
{
Push(S,T);//入栈
T->flag = 2;//意味两次入栈
T = T->Right;//转为访问右子树
}
else
{
printf(" %c",T->Data);//访问数据
T = NULL;
}
}
}
}
详细:原文链接:https://blog.csdn.net/weixin_43906799/article/details/106737596
Java版本实现
对代码的理解(多画几个图多画几遍,不信不理解哼╭(╯^╰)╮):
- 先序遍历:根左右 根入栈,栈不空时,根出栈并打印,右子节点入栈,左子节点入栈
- 中序遍历:栈不空或者当前节点不空条件下,不断让左子节点入栈,为空时,出栈并打印
- 后序遍历:设计两个栈,根节点入栈,栈1不空,则将其转移到栈2,转移节点的左右子节点入栈1,最后栈2 打印后序遍历结果