中国大学MOOC-陈越、何钦铭-数据结构 Tree Traversals Again

题目描述:
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

思考:
这道题其实是利用树的先序,中序遍历结果来得到后续遍历结果。把输入的Push的元素按顺序输出就可以先序遍历结果。把Pop的元素按顺序输出就可以得到中序遍历结果。不过,因为在输入中Pop并没有输入数字,所以要利用Push的元素来得到Pop的结果。所以我的想法是利用一个数组,命名为Visited,大小和Push输入的大小一样,为N。Visited的作用是标记Push数组的元素是否被访问过,它的下标和Push数组的下标保持一致。同时Pop数组的下标和Push的下标保持一致,当输入为Pop时,记录下此时Pop数组的下标,并在Visited数组中从后往前查找最近一个未被访问过的Push元素,此时这个元素也是将要被Pop出来的元素。这就是得到中序遍历结果的方法。
接下来就是利用先序遍历,中序遍历得到后续遍历结果。对于先序遍历,它的第一个元素就是根节点,而对于后续遍历,它的最后一个元素才是根节点。所以我们就可以依次先得到根节点。接着我们可以去中序遍历数组的中找到这个根节点,并且根据中序遍历的特点可以得到,在中序遍历中,根节点左边的就是左子树,根节点右边的就是右子树。于是对于左右子树,我们便可以分而治之,也采用类似的方法,递归调用函数。

代码如下:

#include<iostream>
#include<string>
using namespace std;
#define MaxNumber 30//TreeNode数组所拥有的最大容量
typedef struct TreeNode *Order;
struct TreeNode{
    string C;//记录输入的字符串值
    int Key;//记录输入的节点值
};
TreeNode PreOrder[MaxNumber], InOrder[MaxNumber];//存储前序遍历,和中序遍历的节点信息
bool Visited[MaxNumber];//帮助获取前序遍历的信息
int PostOrder[MaxNumber];//后续遍历保存的信息
void Input(int N){
    int i = -1, j ,l=-1,key;
    string s;
    for (int k = 0; k < 2 * N; k++){
        cin >> s;
        if (s == "Push"){//s==Push,把s和所输入的key存入到PreOrder数组中
            cin >> key;
            PreOrder[++i].C = s;
            PreOrder[i].Key = key;
        }
        else{
            if (s == "Pop"){//否则若为POP的话
                j = i;//把当前PreOrder的下标赋给j
                while (Visited[j] == true && j>-1){
                    if (j > 0){ j--; }//j>0才会执行j--
                }   //j往前找,一直找到一个在PreOrder中未被访问的节点,这个节点就是当前要弹出的节点
                InOrder[++l].C == "Pop";//于是执行赋值操作
                InOrder[l].Key = PreOrder[j].Key;
                Visited[j] = true;
            }
        }
    }
}
void solve(int PreL, int InL, int PostL, int n){//PreL代表从PreOrder当前第一个节点的位置,InL,PostL同理。n代表传入的规模
    int root, i;
    int L, R;
    if (n == 0){ return; }
    if (n == 1){ PostOrder[PostL] = PreOrder[PreL].Key; return; }
    root= PreOrder[PreL].Key;//找出当前的根节点
    PostOrder[PostL + n - 1] = root;//把根节点插入到后序遍历的数组中
    for (i = 0; i < n; i++){//找到在中序遍历数组中此时root位置
        if (InOrder[InL+i].Key == root){ break; }
    }
    L = i;//L表示此时root左边节点个数
    R = n - L - 1;//R表示此时root右边节点个数
    solve(PreL + 1, InL, PostL, L);//分而治之,对左子树递归
    solve(PreL + L + 1, InL + L + 1, PostL + L, R);//对右子树递归

}
int main(){
    int N;
    cin >> N;
    Input(N);
    solve(0, 0, 0, N);
    for (int i = 0; i < N - 1; i++){
        cout <<PostOrder[i] << " ";
    }
    cout << PostOrder[N-1];
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值