目录
题干:
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
解题思路:
输入数据为一些列关于栈的操作,仔细观察会发现其出栈的序列是二叉树的中序遍历,入栈序列是二叉树的先序遍历,只需将两个序列提取出来,便可以很容易地构建一棵二叉树,然后对二叉树进行后续遍历即可得到二叉树的后序遍历序列。
按照解题思路,一共分为三个步骤:
1.建栈,构造先序序列和中序序列
2.构造二叉树
3.后序遍历二叉树,输出结果
1.建栈
这里用的是C语言,所以需要自己造轮子,只需写初始化栈、入栈、出栈操作即可,比较简单:
typedef struct Stack Stack;
struct Stack
{
int* stack;
int top, size;
};
Stack* initStack(int size) {
Stack* st = (Stack*)malloc(sizeof(Stack));
st->stack = (int*)malloc(sizeof(int) * size);
st->top = -1;
st->size = size;
return st;
}
int popElem(Stack* st) {
if (st->top == -1) //判空,但是这里可有可无
return ERROR;
return st->stack[st->top--];
}
int pushElem(Stack* st, int e) {
if (st->top == st->size) //判满,同样可有可无
return ERROR;
st->stack[++st->top] = e;
return OK;
}
然后在主函数中就可以构造先中序序列了:
char opt[5];
int num; scanf("%d", &num);
int* in = (int*)malloc(sizeof(int) * (num + 1)), * pre = (int*)malloc(sizeof(int) * (num + 1));
Stack* st = initStack(num);
TNode* root = NULL;
for (int i = 1, j = 1; i + j <= num * 2 + 1;) {
scanf("%s", opt);
if (opt[1] == 'u') {
scanf("%d", &pre[i]);
pushElem(st, pre[i]);
i++;
}
else {
in[j] = popElem(st);
j++;
}
}
改进:
关于建栈操作其实可以简化,只需要一个数组模拟栈操作就行了:
char opt[5];
int num, top = 1; scanf("%d", &num);
int* in = (int*)malloc(sizeof(int) * (num + 1)),
* pre = (int*)malloc(sizeof(int) * (num + 1)),
* st = (int*)malloc(sizeof(int) * (num + 1)); //模拟栈
TNode* root = NULL;
for (int i = 1, j = 1; i + j <= num * 2 + 1;) {
scanf("%s", opt);
if (opt[1] == 'u') {
scanf("%d", &pre[i]);
st[top++] = pre[i];
i++;
}
else {
in[j] = st[--top];
j++;
}
}
2.构造二叉树
首先给出节点定义:
typedef struct TreeNode TNode;
struct TreeNode
{
int data;
TNode* left, * right;
};
接下来也就是最核心的部分——根据先序和中序序列构造二叉树。虽然这一步看起来很难,但实际思路理解起来并不难。函数需要6个参数,前两个参数自然是先中序序列不说,后四个则是树的节点在两序列中的范围:
TNode* buildTree(int* in, int* pre, int preBegin, int preEnd, int inBegin, int inEnd);
根据先序序列的特点我们可以看出来,对每一棵树(包括子树)来讲,先序遍历中的第一个节点就是它的根节点,所以我们只要确定每棵子树在先序序列中的范围,就能找到它的根节点,我们首先构造根节点,将根节点的数据存入,然后找出根节点在中序序列中的位置,根据中序序列的特点可知:根节点左右的节点就是该节点的左右子树,因而我们可以求出该根节点左右子树上的节点数量,由此可以确定子树节点在两序列中的范围。如果发现左右子树上的节点数量还大于0,我们就继续递归;如果为0,就说明该节点已经是叶节点,无需继续递归,直接将left和right设置为NULL即可。最后构造完成返回根节点:
TNode* buildTree(int* in, int* pre, int preBegin, int preEnd, int inBegin, int inEnd) {
int leftLen, rigthLen, r; //leftLen = 左子树节点个数 rightLen = 右子树节点个数 r = 根节点在中序序列中的位置
TNode* root = (TNode*)malloc(sizeof(TNode)); //构造根节点
root->data = pre[preBegin]; //将根节点的数据存入根节点
for (r = inBegin; in[r] != root->data; r++); //寻找根节点在中序序列中的位置
leftLen = r - inBegin; //计算左子树节点个数
rigthLen = inEnd - r; //计算右子树节点个数
if (leftLen) //如果左子树不为空,继续构造子树
root->left = buildTree(in, pre, preBegin + 1, preBegin + leftLen, inBegin, inBegin + leftLen - 1);
else //如果为空,则设置左节点为NULL
root->left = NULL;
if (rigthLen) //如果右子树不为空,继续构造子树
root->right = buildTree(in, pre, preEnd - rigthLen + 1, preEnd, inEnd - rigthLen + 1, inEnd);
else //如果为空,则设置右节点为NULL
root->right = NULL;
return root; //返回根节点
}
3.后序遍历输出结果
这一步没什么好说的,唯一值得注意的是末尾不能有多余空格,因而我采取了一些方法:
void postTraversal(TNode* root) {
if (!root)
return;
static int flag = 1;
postTraversal(root->left);
postTraversal(root->right);
if (flag) {
printf("%d", root->data);
flag = 0;
}
else
printf(" %d", root->data);
}
完整代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct TreeNode TNode;
struct TreeNode
{
int data;
TNode* left, * right;
};
TNode* buildTree(int* in, int* pre, int preBegin, int preEnd, int inBegin, int inEnd) {
int leftLen, rigthLen, r;
TNode* root = (TNode*)malloc(sizeof(TNode));
root->data = pre[preBegin];
for (r = inBegin; in[r] != root->data; r++);
leftLen = r - inBegin;
rigthLen = inEnd - r;
if (leftLen)
root->left = buildTree(in, pre, preBegin + 1, preBegin + leftLen, inBegin, inBegin + leftLen - 1);
else
root->left = NULL;
if (rigthLen)
root->right = buildTree(in, pre, preEnd - rigthLen + 1, preEnd, inEnd - rigthLen + 1, inEnd);
else
root->right = NULL;
return root;
}
void postTraversal(TNode* root) {
if (!root)
return;
static int flag = 1;
postTraversal(root->left);
postTraversal(root->right);
if (flag) {
printf("%d", root->data);
flag = 0;
}
else
printf(" %d", root->data);
}
int main()
{
char opt[5];
int num, top = 1; scanf("%d", &num);
int* in = (int*)malloc(sizeof(int) * (num + 1)),
* pre = (int*)malloc(sizeof(int) * (num + 1)),
* st = (int*)malloc(sizeof(int) * (num + 1));
TNode* root = NULL;
for (int i = 1, j = 1; i + j <= num * 2 + 1;) {
scanf("%s", opt);
if (opt[1] == 'u') {
scanf("%d", &pre[i]);
st[top++] = pre[i];
i++;
}
else {
in[j] = st[--top];
j++;
}
}
root = buildTree(in, pre, 1, num, 1, num);
postTraversal(root);
return 0;
}
运行结果: