中国大学MOOC-陈越、何钦铭-数据结构 Tree Traversals Again
2015-10-19 19:18
736 查看
题目描述:
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出来的元素。这就是得到中序遍历结果的方法。
接下来就是利用先序遍历,中序遍历得到后续遍历结果。对于先序遍历,它的第一个元素就是根节点,而对于后续遍历,它的最后一个元素才是根节点。所以我们就可以依次先得到根节点。接着我们可以去中序遍历数组的中找到这个根节点,并且根据中序遍历的特点可以得到,在中序遍历中,根节点左边的就是左子树,根节点右边的就是右子树。于是对于左右子树,我们便可以分而治之,也采用类似的方法,递归调用函数。
代码如下:
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]; }
相关文章推荐
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构揭秘一
- 数据结构之Treap详解
- JavaScript数据结构和算法之图和图算法
- Java数据结构及算法实例:冒泡排序 Bubble Sort
- Java数据结构及算法实例:插入排序 Insertion Sort
- Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture
- java数据结构之java实现栈
- java数据结构之实现双向链表的示例
- Java数据结构及算法实例:选择排序 Selection Sort
- Java数据结构及算法实例:朴素字符匹配 Brute Force
- Java数据结构及算法实例:汉诺塔问题 Hanoi
- Java数据结构及算法实例:快速计算二进制数中1的个数(Fast Bit Counting)
- java数据结构和算法学习之汉诺塔示例
- Java数据结构及算法实例:三角数字
- Java数据结构之简单链表的定义与实现方法示例
- 数据结构之AVL树详解
- qqwry.dat的数据结构图文解释第1/2页
- JavaScript中数据结构与算法(五):经典KMP算法