探索 前序=》后序

L2-004 这是二叉搜索树吗? (25 分)|二叉搜索树性质:前序遍历->后序遍历

假设它是二叉搜索树,一开始isMirror为FALSE,根据二叉搜索树的性质将已知的前序转换为后序,转换过程中,如果发现最后输出的后序数组长度不为n,那就设isMirror为true,然后清空后序数组,重新再转换一次(根据镜面二叉搜索树的性质),如果依旧转换后数组大小不等于n,就输出NO否则输出YES 原文链接:https://blog.csdn.net/liuchuo/article/details/52160484

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. typedef pair<int, int> PII;
  5. #define FOR(i, n, m) for (int i = n; i < m; ++i)
  6. int n, pre[1005];
  7. vector<int> resv;
  8. bool is_mir = 0;
  9. void solve(int root, int tail) {
  10. if (root > tail) return;
  11. int i = root + 1, j = tail; // 用双指针是因为不能确定他是二叉搜索树,单指针可能误判
  12. if (!is_mir) {
  13. while (i <= tail && pre[i] < pre[root]) i++; //找该节点的左子树
  14. while (j > root && pre[j] >= pre[root]) j--; //找该节点的右子树
  15. } else {
  16. while (i <= tail && pre[i] >= pre[root]) i++;
  17. while (j > root && pre[j] < pre[root]) j--;
  18. }
  19. solve(root + 1, i - 1);
  20. solve(j + 1, tail);
  21. resv.push_back(pre[root]);
  22. }
  23. int main() {
  24. cin >> n;
  25. FOR(i, 0, n) cin >> pre[i];
  26. solve(0, n - 1);
  27. if (resv.size() != n) {
  28. resv.clear();
  29. is_mir = 1;
  30. solve(0, n - 1);
  31. }
  32. if (resv.size() != n) {
  33. cout << "NO" << endl;
  34. } else {
  35. cout << "YES" << endl;
  36. FOR(i, 0, resv.size()) {
  37. if (i != 0) cout << " ";
  38. cout << resv[i];
  39. }
  40. }
  41. return 0;
  42. }

前序+中序=>后序

因为前序(根左右)最先出现的总是根结点,所以令root为前序中当前的根结点下标(并且同时把一棵树分为左子树和右子树)。start为当前需要打印的子树在中序中的最左边的下标,end为当前需要打印的子树在中序中最右边的下标。递归打印这棵树的后序,递归出口为start > end。i为root所表示的值在中序中的下标,所以i即是分隔中序中对应root结点的左子树和右子树的下标。
先打印左子树,后打印右子树,最后输出当前根结点pre[root]的值。 https://www.liuchuo.net/archives/2087

  1. #include <cstdio>
  2. using namespace std;
  3. int pre[] = {1, 2, 3, 4, 5, 6};
  4. int in[] = {3, 2, 4, 1, 6, 5};
  5. void post(int root, int start, int end) {
  6. if(start > end)
  7. return ;
  8. int i = start;
  9. while(i < end && in[i] != pre[root]) i++;
  10. post(root + 1, start, i - 1);
  11. post(root + 1 + i - start, i + 1, end);
  12. printf("%d ", pre[root]);
  13. }
  14. int main() {
  15. post(0, 0, 5);
  16. return 0;
  17. }

i-start 其实就是 leftSize
image.png图片来自公众号labuladong

前序+中序=>层序

L2-011 玩转二叉树 (25 分)

关于镜面反转一棵树,只需要在记录 下标时,左孩子为2 index + 2, 右孩子为2 index + 1,在递归完成后level数组中非-1的数就是按照下标排列的层序遍历的顺序

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. vector<int> pre, in, level(10000,-1);
  4. void levelorder(int root, int start, int end, int index){
  5. if(start>end)return;
  6. int i =start;
  7. while(i<end && in[i] != pre[root])i++;
  8. level[index] = pre[root];
  9. levelorder(root + 1, start, i - 1, 2 * index + 2);
  10. levelorder(root + 1 + i - start, i + 1, end, 2 * index + 1 );
  11. }
  12. int main()
  13. {
  14. ios::sync_with_stdio(false);
  15. int n, cnt = 0;
  16. cin>>n;
  17. in.resize(n);
  18. pre.resize(n);
  19. for(int i = 0;i<n;i++)cin>>in[i];
  20. for(int i = 0; i<n;i++)cin>>pre[i];
  21. levelorder(0,0,n-1,0);
  22. for(int i =0;i<level.size();i++){
  23. if(level[i] != -1 && cnt != n-1){
  24. cout<<level[i]<<" ";
  25. cnt++;
  26. }else if(level[i] != -1){
  27. cout<<level[i];
  28. break;
  29. }
  30. }
  31. return 0;
  32. }

后序+中序=>层序

L2-006 树的遍历 (25 分)

层序遍历利用 map 的有序性来完成。
传入左孩子、右孩子下标即可。
image.png

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. vector<int> post,in;
  4. map<int,int> level;
  5. void pre(int root, int start, int end, int index){
  6. if(start > end)return;
  7. int i=start;
  8. while(i<end && in[i] != post[root])i++;//此时 end - i 就是rightSize
  9. level[index] = post[root];
  10. pre(root-1-end+i, start, i-1, 2*index+1);
  11. pre(root-1, i+1, end, 2*index+2);
  12. }
  13. int main()
  14. {
  15. ios::sync_with_stdio(false);
  16. int n;cin>>n;
  17. post.resize(n);
  18. in.resize(n);
  19. for(int i =0;i<n;i++)cin>>post[i];
  20. for(int i =0;i<n;i++)cin>>in[i];
  21. pre(n-1,0,n-1,0);
  22. auto it = level.begin();
  23. cout<<it->second;
  24. while(++it!=level.end())printf(" %d",it->second);
  25. return 0;
  26. }

完全二叉树+后序=> 层序遍历

L2-035 完全二叉树的层序遍历 (25 分)

https://pintia.cn/problem-sets/994805046380707840/problems/1336215880692482058
post中保存输入的后序遍历序列,在sequ保存从根节点开始按层序遍历序列的序号。深度优先搜索index标表示当前节点,大于n则返回。按照完全二叉树的遍历原理进行后序遍历,先进入左右子树(编号为index2 和 index2+1,即index右移1位,和index右移1位+1),cnt为后序遍历的位置标记,并将当前所在的后序遍历的元素,填入sequ[index]

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define FOR(i,n,m) for(int i =n;i<m;++i)
  5. int n,cnt,post[32],sequ[32];
  6. void dfs(int index){
  7. if(index > n)return;
  8. //左右中
  9. dfs(index<<1);//左节点 index*2
  10. dfs(index<<1 | 1);//右节点 index*2+1
  11. sequ[index]=post[cnt++];
  12. }
  13. int main()
  14. {
  15. ios::sync_with_stdio(false);
  16. cin>>n;
  17. FOR(i,0,n)cin>>post[i];
  18. dfs(1);//根节点的下标
  19. cout<<sequ[1];
  20. FOR(i,2,n+1)cout<<" "<<sequ[i];
  21. return 0;
  22. }