An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, the stack operations are: push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). Then a unique binary tree (shown in Figure 1) can be generated from this sequence of operations. Your task is to give the postorder traversal sequence of this tree.
Figure 1
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤30) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 to N). Then 2N lines follow, each describes a stack operation in the format: “Push X” where X is the index of the node being pushed onto the stack; or “Pop” meaning to pop one node from the stack.
Output Specification:
For each test case, print the postorder traversal sequence of the corresponding tree in one line. A solution is guaranteed to exist. All the numbers must be separated by exactly one space, and there must be no extra space at the end of the line.
Sample Input:
6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop
Sample Output:
3 4 2 6 5 1
有些人可能对于英语题目很烦,我先把题目的大概意思讲一下,
文章是让你用栈的相关操作来操作元素,栈最后输出的元素和树有什么关系,就那上面的图片举个例子,我们可以发现,题目给的例子,栈最后输出的元素竟然是这棵树的中序遍历,同时我们也知道树的先序遍历,如果有认真听过课,我们可以知道有了树的先序和中序我们就那构成一棵树,或者知道了树的后序和中序遍历,我们也能构成一棵树,无论是哪两种,我们都需要中序遍历的存在。
关于如何用中序和先序或者是用后序和中序来构成一棵树:
链接: https://blog.csdn.net/shenbossed/article/details/106219675.
首先我们给出栈和树的节点的定义:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 30
typedef struct stack *PtrToSNode;
typedef PtrToSNode Stack;
typedef int ElementType;
struct stack
{
int data;
PtrToSNode next;
};
struct TreeNode
{
int data;
struct TreeNode *left;
struct TreeNode *right;
};
typedef struct TreeNode *BinTree;
这是我们要实现的函数:
BinTree BuildTree(int *pre, int *in, int N);//根据中序和先序来建造一棵树
BinTree CreateTNode();//创造结点
Stack CreatS();//建栈
void push(Stack s,ElementType e);//入栈
ElementType pop(Stack s);//出栈
void PostOrderTravel(BinTree BT,int root);//后序遍历
我们先来看一下主函数:
int main()
{
BinTree BT;
Stack s;
char c[5];
int e,i;
int N;
int pre_item=0,In_item=0;
s=CreatS();
scanf("%d",&N);
getchar();//吸收缓冲字符
int in[N],pre[N];
for(i=0;i<2*N;i++)//栈的操作是元素的两倍push和pop
{
scanf("%s",c);
if(strcmp(c,"Push")==0)//进行push操作
{
scanf("%d",&e);
pre[pre_item++]=e;//存入先序遍历
push(s,e);
}
else
{
in[In_item++]=pop(s);//存入中序遍历
}
}
BT=BuildTree(pre,in,N);//建造树
PostOrderTravel(BT,BT->data);//后序遍历
return 0;
}
首先是简单的栈的操作集:
Stack CreatS()
{
Stack s;
s=(Stack)malloc(sizeof(struct stack));
s->next=NULL;
return s;
}
void push(Stack s,int item)
{
if (s==NULL)
s=CreatS();
Stack t;
t=(Stack)malloc(sizeof(struct stack));
t->data=item;
t->next=s->next;
s->next=t;
return;
}
int pop(Stack s)
{
if(s->next==NULL||s==NULL)
{
printf("栈为空,无法抛出元素!");
return 0;
}
Stack cell;
int m;
cell=(Stack)malloc(sizeof(struct stack));
cell=s->next;
s->next=cell->next;
m=cell->data;
free(cell);
return m;
}
创造一个树节点:
BinTree CreatTNode()
{
BinTree t;
t=(BinTree)malloc(sizeof(struct TreeNode));
t->data=0;
t->left=t->right=NULL;
return t;
}
对于建造树这一块,我希望大家能够好好理解:
BinTree BuildTree(int *pre,int *in,int N)
{
BinTree BT;
ElementType root;
int LeftNum, RightNum, flag, i;
int Left_pre[N], Right_pre[N], Left_in[N], Right_in[N];//定义左前遍历,左中遍历,右前遍历,右中遍历
if(N==1)//只有一个结点
{
BT = CreatTNode();
BT->data = pre[0];
BT->left = NULL;
BT->right = NULL;
return BT;
}
else if(N == 0)
return NULL;//树为空直接返回
else{//树不为空,有两个及以上的节点
root = pre[0];//根节点为先序数组的第一个元素
BT = CreatTNode();
BT->data = root;
flag = LeftNum = RightNum = 0;
for(i=0;i<N;i++)
{
if(in[i]!=root)//先找到中序遍历的根节点在哪里
{
if(flag)//开始flag为0,查找根节点的左子树,当查找完设置flag为1,此时开始查找根节点的右子树
{
Right_in[RightNum++] = in[i];//赋值的同时计算右子树元素的数量
}
else
{
Left_in[LeftNum++] = in[i];//赋值的同时计算左子树元素的数量
}
}
else
{
flag = 1;
}
}
for(i=0;i<LeftNum;i++)//左子树元素数量
Left_pre[i] = pre[i+1];//从根节点之后进行计算
for(i=0;i<RightNum;i++)
Right_pre[i] = pre[LeftNum+i+1];//从根节点加上左子树的元素数量之后进行计算
BT->left = BuildTree(Left_pre,Left_in,LeftNum);//递归建立左子树
BT->right = BuildTree(Right_pre,Right_in,RightNum);//递归建立右子树
return BT;
}
}
当做完这一步的时候,我想大家已经轻松许多了
关于树的后序遍历,我们应该能做出来了
void PostOrderTravel(BinTree BT,int root)
{
if(BT->left)//先左
{
PostOrderTravel(BT->left,root);
}
if(BT->right)//再右
{
PostOrderTravel(BT->right,root);
}
if(BT->data==root)//最后根
{
printf("%d",BT->data);//最后输出根节点
}
else
{
printf("%d ",BT->data);//不是树的总根我们就再打印元素加空格
}
}
总的代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 30
typedef struct stack *PtrToSNode;
typedef PtrToSNode Stack;
typedef int ElementType;
struct stack
{
int data;
PtrToSNode next;
};
struct TreeNode
{
int data;
struct TreeNode *left;
struct TreeNode *right;
};
typedef struct TreeNode *BinTree;
BinTree BuildTree(int *pre, int *in, int N);
BinTree CreateTNode();
Stack CreatS();
void push(Stack s,ElementType e);
ElementType pop(Stack s);
void PostOrderTravel(BinTree BT,int root);
int main()
{
BinTree BT;
Stack s;
char c[5];
int e,i;
int N;
int pre_item=0,In_item=0;
s=CreatS();
scanf("%d",&N);
getchar();
int in[N],pre[N];
for(i=0;i<2*N;i++)
{
scanf("%s",c);
if(strcmp(c,"Push")==0)
{
scanf("%d",&e);
pre[pre_item++]=e;
push(s,e);
}
else
{
in[In_item++]=pop(s);
}
}
BT=BuildTree(pre,in,N);
PostOrderTravel(BT,BT->data);
return 0;
}
Stack CreatS()
{
Stack s;
s=(Stack)malloc(sizeof(struct stack));
s->next=NULL;
return s;
}
BinTree CreatTNode()
{
BinTree t;
t=(BinTree)malloc(sizeof(struct TreeNode));
t->data=0;
t->left=t->right=NULL;
return t;
}
void push(Stack s,int item)
{
if (s==NULL)
s=CreatS();
Stack t;
t=(Stack)malloc(sizeof(struct stack));
t->data=item;
t->next=s->next;
s->next=t;
return;
}
int pop(Stack s)
{
if(s->next==NULL||s==NULL)
{
printf("栈为空,无法抛出元素!");
return 0;
}
Stack cell;
int m;
cell=(Stack)malloc(sizeof(struct stack));
cell=s->next;
s->next=cell->next;
m=cell->data;
free(cell);
return m;
}
BinTree BuildTree(int *pre,int *in,int N)
{
BinTree BT;
ElementType root;
int LeftNum, RightNum, flag, i;
int Left_pre[N], Right_pre[N], Left_in[N], Right_in[N];
if(N==1)
{
BT = CreatTNode();
BT->data = pre[0];
BT->left = NULL;
BT->right = NULL;
return BT;
}
else if(N == 0)
return NULL;
else{
root = pre[0];
BT = CreatTNode();
BT->data = root;
flag = LeftNum = RightNum = 0;
for(i=0;i<N;i++)
{
if(in[i]!=root)
{
if(flag)
{
Right_in[RightNum++] = in[i];
}
else
{
Left_in[LeftNum++] = in[i];
}
}
else
{
flag = 1;
}
}
for(i=0;i<LeftNum;i++)
Left_pre[i] = pre[i+1];
for(i=0;i<RightNum;i++)
Right_pre[i] = pre[LeftNum+i+1];
BT->left = BuildTree(Left_pre,Left_in,LeftNum);
BT->right = BuildTree(Right_pre,Right_in,RightNum);
return BT;
}
}
void PostOrderTravel(BinTree BT,int root)
{
if(BT->left)
{
PostOrderTravel(BT->left,root);
}
if(BT->right)
{
PostOrderTravel(BT->right,root);
}
if(BT->data==root)
{
printf("%d",BT->data);
}
else
{
printf("%d ",BT->data);
}
}