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.
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
题意:用栈的push、pop操作给出一棵二叉树的中序遍历顺序,求这棵二叉树的后序遍历。
这道题我写了两种解法,第一种需要建立树,具体如下:
需要一个堆栈s,一个child变量(表示该当前结点是其父亲结点的左儿子还是右儿子),父亲结点变量fa
对于push x操作:
1).第一个push的肯定是根节点root。
2).根据child变量,建立fa与x的父子关系,fa = x;
3).由于是中序遍历,所以接下来的结点必定是x的左儿子(如果有的话),child = LEFT;
4).然后进行Push x操作,因为未来还要输入x的右儿子(如果有的话),此时有必要记住x结点
对于pop操作:
1).根据中序遍历性质,可知接下来的结点必定是当前堆栈顶部结点的右儿子(如果有的话),因此fa = Pop(),child = RIGHT;
代码实现如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define ElementType int
#define MaxN 35
#define LEFT 0
#define RIGHT 1
typedef struct SNode *Stack;
struct SNode{
ElementType *data;
int top;
int MaxSize;
};
struct TreeNode{
int left;
int right;
}node[MaxN];
Stack CreateStack(int MaxSize);
void Push(Stack PtrS,ElementType X);
ElementType Pop(Stack PtrS);
void PostOrderTraversal(int r);
int main()
{
int N,x;
int root = -1,fa;
int child = LEFT;
char str[10];
Stack s = CreateStack(100);
memset(node,-1,sizeof(node));
scanf("%d",&N);
for(int i=0; i<2*N; i++){
scanf("%s",str);
if(strcmp(str,"Push") == 0){
scanf("%d",&x);
if(root == -1){
root = x; //第一个输入的必是根结点
}else{
if(child == LEFT){
node[fa].left = x;
}else{
node[fa].right = x;
}
}
fa = x;
child = LEFT;
Push(s,x);
}else{
fa = Pop(s);
child = RIGHT;
}
}
PostOrderTraversal(root);
return 0;
}
/*****后序遍历*****/
void PostOrderTraversal(int r)
{
static int first = 1;
if(r != -1){
PostOrderTraversal(node[r].left);
PostOrderTraversal(node[r].right);
if( first ){
first = 0;
printf("%d",r);
}else{
printf(" %d",r);
}
}
}
//建立空栈
Stack CreateStack(int MaxSize)
{
Stack S = (Stack)malloc(sizeof(struct SNode));
S->data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
S->top = -1;
S->MaxSize = MaxSize;
return S;
}
//入栈
void Push(Stack S,ElementType X)
{
if(S->top == S->MaxSize-1)
printf("堆栈满\n");
else
S->data[++(S->top)] = X;
}
//出栈
#define Error -1
ElementType Pop(Stack S)
{
if(S->top == -1){
printf("空栈\n");
return Error;
}else{
return (S->data[(S->top)--]);
}
}
第二种解决方法不需要建立树。因为题目给出的是非递归的中序遍历,那么其实在它的堆栈操作中,Push结点的顺序就是先序遍历的顺序,Pop结点的顺序就是中序遍历的顺序,那么我们就可以根据先序和中序遍历的顺序通过递归求解“左右子树”后序遍历顺序的方式求出后序遍历的顺序。
具体代码实现为:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define ElementType int
#define MaxN 35
typedef struct SNode *Stack;
struct SNode{
ElementType *data;
int top;
int MaxSize;
};
int pre[MaxN],in[MaxN],post[MaxN]; //存储先序、中序、后序遍历的数组
Stack CreateStack(int MaxSize);
void Push(Stack PtrS,ElementType X);
ElementType Pop(Stack PtrS);
void Post_solve(int preL,int inL,int postL,int n);
int main()
{
int i,j=0,k=0,x,N;
int first = 1;
char str[10];
scanf("%d",&N);
Stack s = CreateStack(N);
for(int i=0; i<2*N; i++){
scanf("%s",str);
if(strcmp(str,"Push") == 0){
scanf("%d",&x);
pre[j++] = x;
Push(s,x);
}else{
in[k++] = Pop(s);
}
}
Post_solve(0,0,0,N);
for(i=0; i<N; i++){
if( first ){
first = 0;
printf("%d",post[i]);
}else{
printf(" %d",post[i]);
}
}
return 0;
}
void Post_solve(int preL,int inL,int postL,int n)
{/*preL,inL,postL分别表示当前遍历数组的最左端*/
int i,root;
int Left,Right;
if( n == 0 ) return; //当递归至只有没有数时,直接返回
if( n == 1 ){
post[postL] = pre[preL]; //当递归至只有一个数时,先序,中序,后序的数组里面的值是相等的
return;
}
root = pre[preL]; //当前树的根结点肯定是先序遍历的第一个结点
post[postL+n-1] = root; //在后序遍历中,当前树的根结点肯定是最后访问的
for(i=0; i<n; i++){/*在中序遍历中找到当前树的根结点*/
if( in[inL+i] == root ) break;
}
Left = i; //当前树的左子树所包含的结点数
Right = n-Left-1; //当前树的右子树所包含的结点数
Post_solve(preL+1,inL,postL,Left); //递归解决左子树的后序遍历
Post_solve(preL+Left+1,inL+Left+1,postL+Left,Right); //递归解决右子树的后序遍历
}
//建立空栈
Stack CreateStack(int MaxSize)
{
Stack S = (Stack)malloc(sizeof(struct SNode));
S->data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
S->top = -1;
S->MaxSize = MaxSize;
return S;
}
//入栈
void Push(Stack S,ElementType X)
{
if(S->top == S->MaxSize-1)
printf("堆栈满\n");
else
S->data[++(S->top)] = X;
}
//出栈
#define Error -1
ElementType Pop(Stack S)
{
if(S->top == -1){
printf("空栈\n");
return Error;
}else{
return (S->data[(S->top)--]);
}
}
转载来源:https://blog.csdn.net/Authur520/article/details/84865461