二叉树
已知前序(先序)与中序输出后序
先序确定根,中序确定左右孩子
- 从头开始,在中序序列里面找根,置为i,while里的另一个条件是
while(i<end)
- 输出后序就是你的位置应该在三个中的第三个
- 左子树的根为
root+1
右子树的根为root+1+i-start
- 结果就是你前序序列(下标是root)
- 然后你可以完全信任柳神,这里的start 还有 end 都是下标
#include <cstdio>
using namespace std;
int pre[] = {1, 2, 3, 4, 5, 6};
int in[] = {3, 2, 4, 1, 6, 5};
void post(int root, int start, int end) {
if(start > end)
return ;
int i = start;
while(i < end && in[i] != pre[root]) i++;
post(root + 1, start, i - 1);
post(root + 1 + i - start, i + 1, end);
printf("%d ", pre[root]);
}
int main() {
post(0, 0, 5);
return 0;
}
已知后序与中序输出前序(先序)
- 从头开始,在中序序列里面找根,置为i,while里的另一个条件是
while(i<end)
- 输出后序就是你的位置应该在三个中的第三个
- 左子树的根为
root-1 + i - end
右子树的根为root-1
- 左子树和右子树的根,这一点要特别注意一下
- 结果就是你的后序序列(下标是root)
#include <cstdio>
using namespace std;
int post[] = {3, 4, 2, 6, 5, 1};
int in[] = {3, 2, 4, 1, 6, 5};
void pre(int root, int start, int end) {
if(start > end) return ;
int i = start;
while(i < end && in[i] != post[root]) i++;
printf("%d ", post[root]);
pre(root - 1 + i - end, start, i - 1);
pre(root - 1, i + 1, end);
}
int main() {
pre(5, 0, 5);
return 0;
}
已知后序和中序,输出层序
- 然后你可以完全信任柳神,这里的start 还有 end 都是下标
- 就你需要知道的是,但凡是你涉及到了层序,你都需要一个数组来存储里面的东西,也都需要
index * 2
和index * 2+1
这两个东西。(如果是下标从1开始是这样。如果是从0开始就要再多加一个1了)
#include <cstdio>
#include <vector>
using namespace std;
vector<int> post, in, level(100000, -1);
void pre(int root, int start, int end, int index) {
if(start > end) return ;
int i = start;
while(i < end && in[i] != post[root]) i++;
level[index] = post[root];
pre(root - 1 - end + i, start, i - 1, 2 * index + 1);
pre(root - 1, i + 1, end, 2 * index + 2);
}
int main() {
int n, cnt = 0;
scanf("%d", &n);
post.resize(n);
in.resize(n);
for(int i = 0; i < n; i++) scanf("%d", &post[i]);
for(int i = 0; i < n; i++) scanf("%d", &in[i]);
pre(n-1, 0, n-1, 0);
for(int i = 0; i < level.size(); i++) {
if(level[i] != -1 && cnt != n - 1) {
printf("%d ", level[i]);
cnt++;
} else if(level[i] != -1){
printf("%d", level[i]);
break;
}
}
return 0;
}
已知二叉树的中序和层序输出树的前序和后序
- 思路就是你用层序和中序去建立起一棵树,树呢,来一个struct,里面放当前结点的数值和左子树右子树的下标
- 先确定根节点,根节点一定是层序遍历的第一个
- 按照层序的顺序把每个节点装入树上。遍历层序是因为层序可以保证当前节点的父节点已经被装入树中了
- 但是根据层序遍历无法确定某个点的父亲节点,所以在插入到树上的过程我们需要从根节点开始插入,然后一层一层往下,直到叶子节点停下,成为新的叶子节点
if (root == -1) {//当前点不存在,插入
a[tot].data = data;
a[tot].nextl = -1;
a[tot].nextr = -1;
tot++;
return;
}
-
如果root是-1就表示这个点是空的,生成新的叶子节点·
-
剩下需要处理的问题就是怎么正确的一层层往下,怎么知道他最终的位置在当前这个节点(即节点root)的左子树中还是右子树中
-
观察中序遍历我们可以发现,如果在当前节点的左子树中,那么需要插入的这个节点(data)在中序中的位置(index)应该小于当前节点在中序中的位置
-
如果在当前节点的右子树中,那么需要插入的这个节点(data)在中序中的位置(index)应该大于当前节点在中序中的位置
-
判断一下需要往左子树走还是右子树中走即可,需要注意的是如果当前节点已经是叶子节点了,那么更新完后需要更新nextl或者nextr
-
存储位置呢很好存,用一个plaz数组就好
遇到的问题:
- 那个地方存位置你没存清楚
- 添加的逻辑你没弄清楚
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 1100;
int zhong[maxn], cen[maxn];
int plac[maxn];
int n;
struct node {
int data;
int nextl, nextr;
}a[maxn];
int tot = 0;
void add(int root, int data, int index) {
if (root == -1) {//当前点不存在,插入
a[tot].data = data;
a[tot].nextl = -1;
a[tot].nextr = -1;
tot++;
return;
}
int i=plac[a[root].data];//查找当前根的值在需要插入的点的左边还是右边
if (i > index) {
add(a[root].nextl, data, index);
if (a[root].nextl == -1)a[root].nextl = tot - 1;
}
else {
add(a[root].nextr, data, index);
if (a[root].nextr == -1)a[root].nextr = tot - 1;
}
}
void pro(int root) {
if (root == -1)return;
cout << a[root].data << " ";
pro(a[root].nextl);
pro(a[root].nextr);
}
void hou(int root) {
if (root == -1)return;
hou(a[root].nextl);
hou(a[root].nextr);
cout << a[root].data << " ";
}
int main() {
int t;
cin >> t;
while (t--) {
memset(a,0,sizeof(a));
tot = 1;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> cen[i];//层序
}
for (int i = 0; i < n; i++) {
cin >> zhong[i];//中序
plac[zhong[i]]=i;
}
a[0].data = cen[0];
a[0].nextl = -1;
a[0].nextr = -1;
for (int i = 1; i < n; i++) {
add(0, cen[i], plac[cen[i]]);
}
pro(0);
cout << endl;
hou(0);
cout << endl;
}
}
完全二叉树
给你完全二叉树的后序遍历,让你弄出它的层序遍历。
- 也就是说,只要是涉及到层序遍历的,都要设计一个下标。
- 然后你的先序遍历和后序遍历的用处就是为了给你一个按照左右根或者左根右顺序走的条件。
就说实话,你的学习资料的优质与否对你的影响是天差地别的,之前我看了老师的答案,垃圾得一批,搞得我以为很难,一直不敢做。现在看了柳婼的代码,确实好啊。
- 首先明确一点,如果你把二叉树看成是一个一维数组,那么你的层序遍历就是按照顺序去走一边你的数组,后序遍历就是按照
idx*2
,idx*2+1
,idx
的递归顺序去走一遍。 - 在递归之中模拟后序遍历的过程,在后序遍历时,传递的是你后序遍历时候的下标
- 按照这个下标的顺序去把后序遍历的内容填进来
#include <bits/stdc++.h>
using namespace std;
int n, cnt, In[32], dfs[32];
void Func(int index) {
if (index > n) return;
Func(index << 1);
Func(index << 1 | 1);
dfs[index] = In[cnt++];
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> In[i];
Func(1);
cout << dfs[1];
for (int i = 2; i <= n; i++) cout << ' ' << dfs[i];
return 0;
}