[二叉树]关于前序、中序、后序、层序序列
一些概念
满二叉树(Full Binary Tree) 和 完全二叉树(Complete Binary Tree) 是两个不同的概念
🟥 满二叉树(Full Binary Tree)->必须完全填满
- 每个非叶子节点都有两个孩子
- 或者说:每个节点要么是叶子节点,要么有 两个孩子
- 举例:
A/ \B C/ \ / \D E F G
🟨 完全二叉树(Complete Binary Tree)->最后一层可以不填满
- 从上到下、从左到右依次填满
- 只有最后一层可以不满,但必须从左往右连续填充
- 举例:
A/ \B C/ \ / D E F
存树方式
一共n
个节点
开一个数组int tree[n<<2]
4倍大小
node<<1
表示左子树
node<<1|1
表示右子树
tree[]
中存的就是层序序列
GPT的介绍
✅ 哪些组合能唯一建树?
提供的遍历 | 是否能唯一建树? | 说明 |
---|---|---|
中序 + 前序 | ✅ 能 | 最常见、能唯一建树 |
中序 + 后序 | ✅ 能 | 也可以唯一建树 |
前序 + 后序 | ❌ 一般不行 | 除非是满二叉树才行 |
只有一种遍历 | ❌ 不能 | 信息不够,多种可能的树 |
必须有一个中序序列 才能唯一确定一颗二叉树
🤔 那如果是“完全二叉树”呢?
如果你明确知道这棵树是完全二叉树,那情况就不一样了:
✅ 只要你给出:
- 前序遍历 + 完全二叉树信息 👉 可以唯一建树
- 后序遍历 + 完全二叉树信息 👉 可以唯一建树
- 中序遍历 + 完全二叉树信息 👉 可以唯一建树
- 层序遍历 👉 本身就能唯一确定完全二叉树
🌳 完全二叉树的关键特点是:节点编号是固定的!
比如:
1 -> root
2 -> left of root
3 -> right of root
4 -> left of node 2
...
这就是你前面用 node<<1
、node<<1|1
的核心!
✅ 小结
遍历方式 | 是否能唯一建树? |
---|---|
前序+中序 / 中序+后序 | ✅ |
层序 + 完全二叉树 | ✅ |
前序/后序 + 完全二叉树结构 | ✅ |
只有一种遍历 | ❌ |
前序+后序 | ❌(除非满二叉树) |
如何通过给定的序列确定一颗树?
一、中序+X
- X要么是先序 要么是后序
- 核心就是通过X确定根在哪里
- 再从中序中找到根的位置
- 左右两边就是左右子树 再递归左右两边建树
1.中序+后序->先序
const int N = 10;
int in[N],post[N],tree[N<<2];
int n;//inl表示当前子树在中序序列中的起点 postl 后序序列起点
//len表示当前子树长度 (节点个数)
//pos用来分配节点在tree数组中的下标(pos<<1 左子树,pos<<1|1 右子树)
void build(int inl,int postl,int len,int pos){int root = post[postl+len-1];tree[pos]=root;if(len==1) return;int i=0;while(in[inl+i]!=root) i++;//在中序序列中找到根的下标int l=i,r=len-i-1;//l,r为左右子树长度//左右子树非空就递归建树if(l) build(inl, postl,l,pos<<1);if(r) build(inl+l+1,postl+l,r,pos<<1|1);
}void preprint(int node){if(node>n*4||tree[node]==0){return;}cout<<(char)(tree[node]-1+'A');preprint(node<<1);preprint(node<<1|1);
}void solve(){string s;cin>>s;for(int i=0;i<s.size();i++){in[i]=s[i]-'A'+1;}cin>>s;for(int i=0;i<s.size();i++){post[i]=s[i]-'A'+1;}n=s.size();build(0,0,n,1);preprint(1);
}
中序+先序->后序
const int N = 2010;
int tree[N<<2],pre[N],in[N];
int n;void build(int inl,int prel,int len,int pos){int root=pre[prel];tree[pos]=root;if(len==1) return;int i=0;while(in[inl+i]!=root) i++;int l=i,r=len-i-1;if(l) build(inl,prel+1,l,pos<<1);if(r) build(inl+l+1,prel+l+1,r,pos<<1|1);
}void postprint(int node){if(tree[node]==-1){return;}postprint(node<<1);postprint(node<<1|1);cout<<(char)(tree[node]-1+'A');
}void solve(){string s;while(cin>>s){n=s.size();memset(tree,-1,sizeof tree);memset(pre,0,sizeof pre);memset(in,0,sizeof in);for(int i=0;i<s.size();i++){pre[i]=s[i]-'A'+1;}cin>>s;for(int i=0;i<s.size();i++){in[i]=s[i]-'A'+1;}build(0,0,n,1);postprint(1);cout<<endl;}
}
给定完全二叉树+某一种序列
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;const int MAXN = 2005;
char tree[MAXN]; // 用数组模拟树,编号从1开始
string s; // 前序输入的字符串(含#)
int pos; // 当前在字符串中处理到的位置// 建树,参数是当前处理到的节点编号
void build(int node) {if (pos >= s.size()) return;if (s[pos] == '#') {pos++; // 空节点,跳过return;}tree[node] = s[pos++]; // 建立当前节点build(node << 1); // 左儿子build(node << 1 | 1); // 右儿子
}// 中序遍历
void inOrder(int node) {if (tree[node] == 0) return;inOrder(node << 1);cout << tree[node];inOrder(node << 1 | 1);
}// 后序遍历
void postOrder(int node) {if (tree[node] == 0) return;postOrder(node << 1);postOrder(node << 1 | 1);cout << tree[node];
}// 层序遍历
void levelOrder(int root) {queue<int> q;if (tree[root]) q.push(root);while (!q.empty()) {int u = q.front(); q.pop();cout << tree[u];if (tree[u << 1]) q.push(u << 1);if (tree[u << 1 | 1]) q.push(u << 1 | 1);}
}void levelOrder(){//这样也可以 因为tree中存的就是层序序列int n=s.size();for(int i=1;i<n*4;i++){if(tree[i]) cout<<tree[i];}
}
int main() {while (cin >> s) {memset(tree, 0, sizeof(tree));pos = 0;build(1); // 从1号节点开始建树inOrder(1);cout << " ";postOrder(1);cout << " ";levelOrder(1);cout << endl;}return 0;
}
先序
void build(int node) {if (pos >= s.size()) return;if (s[pos] == '#') {pos++; // 空节点,跳过return;}tree[node] = s[pos++]; // 建立当前节点build(node << 1); // 左儿子build(node << 1 | 1); // 右儿子
}
中序
gpt写的 不太懂
string in;
int tree[N<<2];
int build( int& index, int l, int r) {if (l > r) return -1; // 递归出口// 选择当前节点int mid = (l + r) / 2;if (in[mid] == '#') {return -1; // 当前节点为空}// 生成当前节点,并填充到树中int node = index++;tree[node] = in[mid] - '0'; // 假设树节点的值为数字字符// 递归构建左子树int left = build(index, l, mid - 1);// 递归构建右子树int right = build(index, mid + 1, r);return node;
}