板子:用前序 + 中序建树
前序的第一个元素是根;在中序里找到根,根的左边是左子树,右边是右子树。数出左子树有
len个结点,就能在前序里划出左右子树的范围,然后递归。
代码
BiTree build(int pre[], int pl, int pr, int in[], int il, int ir) { // 用 pre[pl..pr] 和 in[il..ir] 建树
if (pl > pr) return NULL; // 区间为空:空树
BiTNode *T = (BiTNode *)malloc(sizeof(BiTNode));
T->data = pre[pl]; // 前序的第一个就是根
int k = il;
while (in[k] != pre[pl]) k++; // 在中序里找到根的位置 k
int len = k - il; // 左子树的结点个数
T->lchild = build(pre, pl + 1, pl + len, in, il, k - 1); // 前序里根后面的 len 个是左子树
T->rchild = build(pre, pl + len + 1, pr, in, k + 1, ir); // 再往后的都是右子树
return T;
}
// 调用:BiTree T = build(pre, 0, n - 1, in, 0, n - 1);复杂度:每层在中序里线性查找根,最坏时间
关键边界:三个序列的区间怎么划分
| 序列 | 左子树 | 根 | 右子树 |
|---|---|---|---|
前序 pre | pl+1 ~ pl+len | pl | pl+len+1 ~ pr |
中序 in | il ~ k-1 | k | k+1 ~ ir |
后序 post(变形) | pl ~ pl+len-1 | pr | pl+len ~ pr-1 |
记法:len 只能从中序里算出来(k - il),前序和后序都靠 len 来切分。
后序 + 中序:根是 post[pr],左右子树按上表第三行切分,代码只需要改两行递归调用。
易错点
- 前序里左子树的范围是
pl + 1到pl + len,不是到k。k是中序的下标,不能拿来算前序的范围。 - 要求结点的值互不相同,否则在中序里找根可能找错。
- 前序 + 后序不能唯一确定一棵二叉树(只有一个孩子时分不清是左孩子还是右孩子)。必须有中序。
链接
- 📕 返回:数据结构代码板子
- ⬅️ 上一篇:找祖先与最近公共祖先
- ➡️ 下一篇:并查集
- 🔗 5.3.1 二叉树的遍历