BiTree PreInCreate(ElemType A[],ElemType B[],int l1,int h1,int l2,int h2) {
//l1,h1为先序的第一个和最后一个结点下标
//l2,h2为中序的第一个和最后一个结点下标
root=(BiTNode*)malloc(sizeof(BiTNode));
root->data=A[l1];
for(i=l2;B[i]!=root->data;i++);
//停止循环时i正好指向根节点
llen=i-l2;
rlen=h2-i;
if(llen)
root->lchild=PreInCreate(A,B,l1+1,l1+llen,l2,l2+llen-1);
else
root->lchild=NULL;
if(rlen)
root->rchild=PreInCreate(A,B,h1-rlen+1,h1,h2-rlen+1,h2);
else
root->rchild=NULL;
return root;
}
这个 `PreInCreate` 函数是用来根据给定的先序遍历和中序遍历数组构造一个二叉树。变量 `A` 和 `B` 分别代表先序遍历和中序遍历的数组。参数 `l1`, `h1`, `l2`, `h2` 指的是我们当前正在处理的 `A` 和 `B` 数组中的起始和结束索引。
### 函数定义
```c
BiTree PreInCreate(ElemType A[], ElemType B[], int l1, int h1, int l2, int h2)
```
- `ElemType` 可能表示存储在数组中的元素的类型。
- `BiTree` 可能是一个指向二叉树节点的指针的别名。
### 创建根节点
```c
root=(BiTNode*)malloc(sizeof(BiTNode));
```
- 分配内存以创建一个新的二叉树节点。`BiTNode` 是一个结构体,表示二叉树的节点。
### 设置根节点的数据
```c
root->data=A[l1];
```
- `A[l1]` 是先序遍历数组的第一个元素,根据先序遍历的性质,这是当前子树的根节点。
### 查找根节点在中序遍历中的位置
```c
for(i=l2; B[i]!=root->data; i++);
```
- 从中序遍历的起始位置 `l2` 开始,寻找与先序遍历中根节点相等的元素。找到之后,`i` 将指向中序遍历中根节点的位置。
### 计算左右子树的长度
```c
llen=i-l2;
rlen=h2-i;
```
- `llen` 表示左子树的长度,即中序遍历中根节点前面的元素数量。
- `rlen` 表示右子树的长度,即中序遍历中根节点后面的元素数量。
### 递归创建左子树
```c
if(llen)
root->lchild=PreInCreate(A, B, l1+1, l1+llen, l2, l2+llen-1);
else
root->lchild=NULL;
```
- 如果左子树长度 `llen` 大于0,则递归地使用先序遍历和中序遍历的相应部分来构建左子树。
- 先序遍历中,左子树的元素紧跟在根节点后面,从 `l1+1` 到 `l1+llen`。
- 中序遍历中,左子树的元素从 `l2` 到 `l2+llen-1`。
### 递归创建右子树
```c
if(rlen)
root->rchild=PreInCreate(A, B, h1-rlen+1, h1, i+1, h2);
else
root->rchild=NULL;
```
- 如果右子树长度 `rlen` 大于0,则递归地使用先序遍历和中序遍历的相应部分来构建右子树。
- 先序遍历中,右子树的元素位于左子树元素之后,从 `h1-rlen+1` 到 `h1`。
- 中序遍历中,右子树的元素从 `i+1` 到 `h2`。
### 返回构建的树
```c
return root;
```
- 最后,函数返回构建的树的根节点。
递归时传入的参数如何确定?
### 左子树的构建
```c
if(llen)
root->lchild=PreInCreate(A, B, l1+1, l1+llen, l2, l2+llen-1);
else
root->lchild=NULL;
```
1. 参数解析:
- `l1+1` 到 `l1+llen`:在先序遍历(数组 `A`)中,根节点之后紧接着的元素都属于左子树。`l1` 是当前根节点的位置,所以 `l1+1` 是左子树的第一个元素。因为左子树的元素数量为 `llen`,所以左子树在先序遍历中的结束位置是 `l1+llen`。
- `l2` 到 `l2+llen-1`:在中序遍历(数组 `B`)中,根节点位置前的所有元素都属于左子树。由于 `i` 是中序遍历中根节点的位置,所以左子树的起始位置是 `l2`,结束位置是 `i-1`,即 `l2+llen-1`。
2. 逻辑解释:
- 这些参数正确地切割了先序和中序遍历的数组段,用于构建左子树。只有当左子树实际存在(即 `llen > 0`)时才进行递归调用;否则,左孩子指针设置为 `NULL`,表示没有左子树。
### 右子树的构建
```c
if(rlen)
root->rchild=PreInCreate(A, B, h1-rlen+1, h1, i+1, h2);
else
root->rchild=NULL;
```
1. 参数解析:
- `h1-rlen+1` 到 `h1`:在先序遍历中,右子树的元素位于所有左子树元素之后,直到最后一个元素。由于左子树和根节点共占据 `l1+llen` 个位置,右子树的起始位置是 `h1-rlen+1`,结束位置是 `h1`。
- `i+1` 到 `h2`:在中序遍历中,根节点位置后的所有元素都属于右子树。`i+1` 是右子树的起始位置,`h2` 是结束位置。
2. 逻辑解释:
- 这些参数确保了从先序和中序遍历的正确段落中切出用于构建右子树的数组。同样地,只有当右子树实际存在(即 `rlen > 0`)时才进行递归调用;否则,右孩子指针设置为 `NULL`,表示没有右子树。