由二叉树的前序遍历字符串得到其中序遍历字符串
Case1:满二叉树
题目描述
给出一棵满二叉树的先序遍历,有两种节点:字母节点(A-Z,无重复)和空节点(#)。要求这个树的中序遍历。输出中序遍历时不需要输出#。满二叉树的层数n满足1<=n<=5。
示例1
Sample Input:
ABC#D#E
Sample Output:
CBADE
Solution:
满二叉树的特征很明显,左右子树结点个数相等,那么以某一个结点为根的子树中,该根节点在先序遍历中排在第一位,其在中序遍历中一定排在最中间的位置上。利用分治的思想,建立一个数组,
根节点插入到数组中间位置,
左子树根节点插入到数组左边的中间位置,
一直这样直至数组左边中间位置已满开始插入到右边数组的中间位置,
依次递归 . . . . . .
以示例为例,遍历前序遍历字符串插入到数组中,最后输出数组中字符串,即为中序遍历字符串。
#include <iostream> #include <string.h> using namespace std; int i; // 全局变量,控制字符串的遍历 string s; void insert(char a[], int left, int right){ // 将字符串各个元素插入数组对应位置 int mid = (left + right) / 2; if(left <= right && a[mid] != s[i]){ a[mid] = s[i++]; insert(a, left, mid-1); insert(a, mid+1, right); } } bool cimi2(int x){ // 判断x是否是2的n次幂 return (x&(x-1))?false:true; } int main(){ while(cin>>s){ int n = s.length(); if(!cimi2(n+1)){ // 判断是否是满二叉树 cout<<"不满足满二叉树"<<endl; } else{ char *A = new char[n]; // 动态分配字符串数组 i = 0; int left = 0, right = n-1; insert(A, left, right); for(int j = 0; j < strlen(A); j++){ if(A[j] != '#'){ cout<<A[j]<<" "; } } cout<<endl; delete [] A; // 回收动态分配的字符串数组 } } return 0; }
Case2:无限制条件的二叉树
题目描述
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
输入描述:
输入包括1行字符串,长度不超过100。输出描述:
可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。示例1
输入
abc##de#g##f###
输出
c b e g d f a
Solution1:
按照题目描述的那样,根据输入的前序遍历字符串建立二叉树,之后对该二叉树进行中序遍历。
#include <iostream> #include <string> using namespace std; string str; int i; struct TreeNode { char val; struct TreeNode *lchild, *rchild; TreeNode(char c) :val(c), lchild(NULL), rchild(NULL) {} }; TreeNode* createTree() { char c = str[i++]; if (c == '#') return NULL; TreeNode *root = new TreeNode(c); // 动态分配一个TreeNode类型存储空间,返回类型为指针 root->lchild = createTree(); root->rchild = createTree(); return root; // 返回动态分配的指针 } void inOrderTraversal(TreeNode* root) { if (!root) return; inOrderTraversal(root->lchild); cout << root->val << " "; inOrderTraversal(root->rchild); } int main() { while (cin >> str) { i = 0; TreeNode *root = createTree(); inOrderTraversal(root); cout << endl;
delete [] root; // 动态分配的存储空间要回收 } return 0; }
Solution2:
//这个实际上就是树的遍历的非递归实现,入栈时访问 = 前序, 出栈时访问 = 中序 #include <iostream> #include <string> #include <stack> using namespace std; int main() { string pre; while(cin >> pre){ stack<char> s; for(auto it : pre){ if(it != '#') s.push(it); else{ if(!s.empty()){ cout << s.top() << ' '; s.pop(); } } } cout << '\n'; } }
两个题目很相似,第一个来自南京大学2018年研究生复试机试第一题;第二个来自牛客网清华大学复试机试题,代码选取其中优秀提交代码,但是对于不同要求的二叉树,其处理方法还是有很大差异的,比如第一个情况建立满二叉树再遍历是比较麻烦的。细细品味这两道题,就能发现它们的精彩之处。