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
思路如下:
(1)从二叉树的非递归遍历对题目进行分析,可以发现入栈序列可视为先序遍历序列,而出栈序列可视为中序遍历序列,而由先序遍历和中序遍历两个序列就不难得到后序遍历序列;
(2)运用递归将先序遍历序列和中序遍历序列转换为后序遍历序列。由先序遍历序列可找到根节点,再由中序遍历序列即可找到其左右子树在先序、中序遍历序列数组中的起始下标和长度。按照这一思路进行递归;
(3)后序遍历中最后访问根节点,所以将根节点的数值存放在存储后序遍历序列的数组的末尾;
(4) 由(3)可知后序遍历数组从后往前生成,则递归时先递归右子树,再递归左子树。
代码如下:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
constexpr auto N = 30;
using namespace std;
int inOrder[N], preOrder[N], postOrder[N];
int stk[N] = { 0 };
int pre_ptr, in_ptr, post_ptr;
int stk_ptr = 0;
void push(int num);
int pop();
void readTraversal(int stack[], int cnt);
void traversalAgain(int inOrder[], int preOrder[], int len);
int main() {
int nodeNum;
cin >> nodeNum;
pre_ptr = in_ptr = 0;
post_ptr = N - 1;
readTraversal(stk, nodeNum);
traversalAgain(inOrder, preOrder, nodeNum);
//后序遍历序列时从后往前生成,则第一个有效值的下标为N-nodeNum
for (int i = N - nodeNum; i < N - 1; i++) {
printf("%d ", postOrder[i]);
}
printf("%d", postOrder[N - 1]);
return 0;
}
void readTraversal(int stk[], int cnt) {
cnt = 2 * cnt;
int tmp;
while (cnt--) {
string str;
cin >> str;
if (!str.compare("Pop")) {
tmp = pop();
inOrder[in_ptr++] = tmp;
}
else {
cin >> tmp;
push(tmp);
preOrder[pre_ptr++] = tmp;
}
}
}
void push(int num) {
stk[stk_ptr++] = num;
}
int pop() {
return stk[--stk_ptr];
}
void traversalAgain(int inOrder[], int preOrder[], int len) {
if (len == 0) return; /*对应子树为空的情况,保证函数能正常退出*/
postOrder[post_ptr--] = preOrder[0]; //将先序遍历序列首值(根节点)传入后续遍历序列中
int rootIdx = 0;//每次递归中将根节点清零,以找到该层递归中子树的根节点下标
for (; rootIdx < len; rootIdx++)//找寻当前树根节点下标
if (inOrder[rootIdx] == preOrder[0]) {
break;
}
traversalAgain(inOrder + rootIdx + 1, preOrder + rootIdx + 1, len - rootIdx - 1);//递归右子树
traversalAgain(inOrder, preOrder + 1, rootIdx);//递归左子树
}
测试结果: