06-树
基本概念
![image-20211028213442226](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028213442226.png)
**结点的度:**结点拥有的分支个数(A1的度为3);
**树的度:**树中各结点度的最大值(上树度为3);
**叶子结点:**度为0的结点(如A3,A4,A5,A6,A7);
**孩子:**A2,A3,A4为A1的孩子;
**双亲:**A2,A3,A4的双亲为A1;
**祖先:**从根到某结点的路径上的所有结点(A1,A2为A5的结点);
子孙:以某结点为根的的子树中的所有结点,都是该结点的子孙(A2 ~ A6为A1的子孙);
**兄弟:**同一个双亲的孩子之间互为兄弟(A2,A3,A4互为兄弟);
**堂兄弟:**A6,A7互为堂兄弟;
![image-20211028214718157](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028214718157.png)
**树的高度:**树中结点的最大层次;
**结点的深度:**从根结点到该结点路径上的结点个数;
**结点的高度:**从某结点往下走可以达到多个叶子结点,其中最长的那条路径上结点的个数几位该结点在树中的高度;
树的存储结构
顺序存储结构
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
结点信息(结构体) | A1 | A2 | A3 | A4 | A5 | A6 |
父结点所在数组下标 | -1 | 0 | 0 | 0 | 1 | 1 |
也可简化成下图
![image-20211028220822817](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028220822817.png)
链式存储结构
//链表结点类型,存储孩子结点的所有路径
typedef struct Branch{
int childIndex;//存储孩子结点的数组下标
Branch *next;
}Branch;
//树结点
typedef struct{
int data;
Branch *first;
}TNode;
![image-20211028221424674](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028221424674.png)
二叉树
1)每个结点最多只有两棵子树(即二叉树中的结点度只能为0、1、2);
2)子树有左右顺序之分不能颠倒;
3)满二叉树通过删除结点可以得到完全二叉树
二叉树可能的形态
![image-20211028222057306](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028222057306.png)
求完全二叉树的高度(h)
满二叉树列举法求高度
![image-20211028222312550](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028222312550.png)
完全二叉树求高度
![image-20211028222603920](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028222603920.png)
公式
![image-20211028222840122](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028222840122.png)
二叉树的性质
**1.**非空二叉树上叶子结点数等于双分支结点数+1
**2.**二叉树的第i层上最多有2i-1(i大于等于1)个结点
**3.**高度(深度)为k的二叉树最多有2k-1(k大于等于1)个结点,也即满二叉树的前k层的结点个数为2k-1
总分支数=总结点树-1;
叶子结点数为N0,单分支结点数为N1,双分支结点数为N2。
总结点数=N0+N1+N2;总分支数=N1+2N2;
{
总
分
支
数
=
总
结
点
数
−
1
总
结
点
数
=
N
0
+
N
1
+
N
2
总
分
支
数
=
N
1
+
2
N
2
\begin{cases} 总分支数=总结点数-1 \\ 总结点数=N_0+N_1+N_2\\ 总分支数=N_1+2N_2\\ \end{cases}
⎩⎪⎨⎪⎧总分支数=总结点数−1总结点数=N0+N1+N2总分支数=N1+2N2
解得:
{
N
0
=
N
2
+
1
,
也
即
下
行
叶
子
结
点
数
=
双
分
支
结
点
数
+
1
;
\begin{cases} N_0=N_2+1,也即下行 \\ 叶子结点数=双分支结点数+1;\\ \end{cases}
{N0=N2+1,也即下行叶子结点数=双分支结点数+1;
一般树(度为m)
叶 子 结 点 数 为 N 0 , 单 分 支 结 点 数 为 N 1 , 双 分 支 结 点 数 为 N 2 , 三 分 支 结 点 数 为 N 3 , . . . m 分 支 结 点 数 为 N m ; { 总 分 支 数 = 总 结 点 数 − 1 总 结 点 数 = N 0 + N 1 + N 2 + . . . + N m 总 分 支 数 = N 1 + 2 N 2 + 3 N 3 . . . + m N m 叶子结点数为N_0,单分支结点数为N_1,双分支结点数为N_2,三分支结点数为N_3,...m分支结点数为N_m; \begin{cases} 总分支数=总结点数-1 \\ 总结点数=N_0+N_1+N_2+...+N_m\\ 总分支数=N_1+2N_2+3N_3...+mN_m\\ \end{cases} 叶子结点数为N0,单分支结点数为N1,双分支结点数为N2,三分支结点数为N3,...m分支结点数为Nm;⎩⎪⎨⎪⎧总分支数=总结点数−1总结点数=N0+N1+N2+...+Nm总分支数=N1+2N2+3N3...+mNm
解得:
{
N
0
=
1
+
N
2
+
2
N
3
+
.
.
.
+
(
m
−
1
)
N
m
;
,
也
即
下
行
叶
子
结
点
数
=
1
+
双
分
支
结
点
数
+
2
倍
三
分
支
结
点
数
+
.
.
+
(
m
−
1
)
倍
m
分
支
结
点
数
;
\begin{cases} N_0=1+N_2+2N_3+...+(m-1)N_m;,也即下行 \\ 叶子结点数=1+双分支结点数+2倍三分支结点数+..+(m-1)倍m分支结点数;\\ \end{cases}
{N0=1+N2+2N3+...+(m−1)Nm;,也即下行叶子结点数=1+双分支结点数+2倍三分支结点数+..+(m−1)倍m分支结点数;
存储结构
顺序存储结构
完全二叉树适应如下存储结构一般二叉树则不适用
![image-20211028225938101](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028225938101.png)
二叉链表存储结构(孩子存储结构)
![image-20211028230345133](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028230345133.png)
typedef struct BTNode{
int data;
struct BTNode *leftChild;
struct BTNode *rightChild;
}BTNode;
A1->leftChild=A2;
A1->rightChild=A3;
A2->leftChild=A4;
A2->rightChild=NULL;
A3->leftChild=A5;
A3->rightChild=NULL;
树的孩子兄弟存储结构
![image-20211028230901465](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211028230901465.png)
typedef struct BTNode{
int data;
struct BTNode *child;
struct BTNode *sibling;//放兄弟
}BTNode;
A1->child=A2;
A1->sibling=NULL;
A2->sibling=A3;
A3->sibling=A4;
A4->sibling=NULL;
//取A1孩子结点A3
A1->child->sibling
遍历
二叉树的遍历
广度优先(层次)遍历
从上到下,从左到右
![image-20211030172152943](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030172152943.png)
深度优先遍历(先序,中序,后序)
**先序:**第一次来到某个结点时访问,所得序列为先序遍历序列(先访问根节点,然后前先遍历左子树,最后先序遍历右子树)
**中序:**第二次来到某个结点时访问,所得序列为中序遍历序列(先访问左子树,然后访问根结点,最后中序遍历右子树)
**后序:**第三次来到某个结点时访问,所得序列为后序遍历序列(先后序遍历左子树,然后后序遍历右子树,最后访问)
![image-20211030172836861](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030172836861.png)
树的遍历
深度优先遍历
树没有中序遍历
如果一颗二叉树由一颗树转换而来那么:
对二叉树进行先序遍历=对原来的树进行先序遍历,
对二叉树进行中序遍历=对原来的树进行后先序遍历;
森林的遍历
![image-20211030174731623](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030174731623.png)
![image-20211030182434813](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030182434813.png)
二叉树遍历-代码(递归)
//下述代码假设Visit()已经定义过,其中包含了对结点p的各种访问操作,例如可以打印出p对应的数值
typedef struct BTNode{
int data;
struct BTNode *leftChild;
struct BTNode *rightChild;
}BTNode;
void r(BTNode *p){
if(p!=NULL){
//(1)Visit(p)得到先序
r(p->leftChild);
//(2)Visit(p)得到中序
r(p->rightChild);
//(3)Visit(p)得到后序
}
}
二叉树遍历-先序-递归
二叉树遍历-中序-递归
二叉树遍历-后序-递归
二叉树遍历-代码(非递归)
![image-20211030212704793](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030212704793.png)
二叉树遍历-先序-非递归
![image-20211030213342650](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030213342650.png)
1.结点1入栈。
2.出栈,输出栈顶结点1,并将1的左右孩子(2、4)入栈;右孩子先入栈,因为对左孩子的访问要先于右孩子,后入栈的会先出栈访问(先右后左)。
3.出栈,输出栈顶结点2,并将2的左右孩子(3、5)入栈。
4.出栈,输出栈顶结点3,3为叶子结点,无孩子,本步无结点入栈。
5.出栈,输出栈顶结点5.
6.出栈,输出栈顶结点4,此时栈空,进入终态。
**遍历序列为:**1,2,3,5,4。
//二叉树先序遍历非递归算法
void preorderNonrecursion(BTNode *bt){
if(bt!=NULL){
BTNode *Stack[maxSize]; //定义一个栈
int top=-1; //初始化栈
BTNode *p;
Stack[++top]=bt; //根结点入栈
while(top!=-1){ //栈空循环退出,遍历结束
p=stack[top--]; //出栈并输出栈顶结点
Visit(p); //Visit()为访问p的函数
if(p->rchild!=NULL){ //栈顶结点的右孩子存在,则右孩子入栈
Stack[++top]=p->rchild;
}
if(p->lchild!=NULL){ //栈顶结点的左孩子存在,则左孩子入栈
Stack[++top]=p->lchild;
}
}
}
}
二叉树遍历-后序-非递归
先序遍历序列:1 2 3 5 4;
后序遍历序列:3 5 2 4 1;
逆后序遍历序列:1 4 2 5 3;
逆后序遍历序列只不过是先序遍历过程中对左右子树遍历顺序交换所得到的结果。
![image-20211030215655352](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030215655352.png)
1.结点1入stack1。
2.stack1元素出栈,并将结点1入Stack2,结点1的左右孩子存在,左孩子结点2入stack1,右孩子结点4入stack1(先左后右)
3.stack1元素出栈,并将出栈结点4入stack2,结点4的左右孩子不存在。
4.stack1元素出栈,并将出栈结点2入stack2,结点2的左右孩子存在,左孩子3入stack1,右孩子5入stack1。
5.stack1元素出栈,并将出栈结点5入stack2。
6.stack1元素出栈,并将出栈结点3入Stack2。
7.此时栈空,stack2中元素自顶向下依次为:3 5 2 4 1,正好为后序遍历序列。
void postorderNonrecursion(BTNode *bt){
if(bt!=NULL){
/*定义两个栈*/
BTNode *Stack1[maxSize]; int top1 = -1;
BTNode *Stack2[maxSize]; int top2 = -1;
BTNode *p = NULL;
Stack1[++top1] = bt;
while(top1!=-1){
p = Stack1[top--];
Stack2[++top2] = p; //这里和先序遍历的区别是输出改为入Stack2
/*下边的两个判断语句和先序遍历有区别,左右孩子的入栈顺序相反*/
if(p->lchild!=NULL){
Stack1[++top1] = p->lchild;
}
if(p->rchild!=NULL){
Stack1[++top1] = p->rchild;
}
while(top2!=-1){
/*出栈序列即为后序遍历序列*/
p = Stack2[top2--];
Visit(p); //Visit()是访问p的函数,在这里执行打印结点值的操作
}
}
}
}
二叉树遍历-中序-非递归
![image-20211030223235920](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030223235920.png)
1.结点1入栈,1左孩子存在。
2.结点2入栈,2左孩子存在。
3.结点3入栈,3左孩子不存在。
4.出栈,输出栈顶结点3,3右孩子不存在。
5.出栈,输出栈顶结点2,2右孩子存在,右孩子5入栈,5左孩子不存在。
6.出栈,输出栈顶结点5,5右孩子不存在。
7.出栈,输出栈顶结点1,1右孩子存在,右孩子4入栈,4左孩子不存在。
8.出栈,输出栈顶结点4,此时栈空,进入终态。
遍历序列为3 2 5 1 4;
由上步骤可以看出,中序非递归遍历过程如下:
1.开始根结点入栈。
2.循环执行如下操作:如果栈顶结点左孩子存在,则左孩子入栈;如果栈顶结点左孩子不存在,则出栈并输出栈顶结点,然后检查右孩子是否存在,如果存在,则右孩子入栈。
3.当栈空时算法结束。
void inorderNorecursion(BTNode *bt){
if(bt!=NULL){
BTNode *Stack[maxSize]; int top=-1;
BTNode *p;
p = bt;
while(top!=-1||p!=NULL){
while(p!=NULL){ //左孩子存在,则左孩子入栈
Stack[++top] = p;
p = p->lchild;
}
if(top!=-1){ //在栈不空的情况下出栈并输出出栈结点
p = Stack[top--];
Visit(p);
p = p->rchild;
}
}
}
}
线索二叉树
中序线索二叉树
逻辑结构
![image-20211031152759980](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211031152759980.png)
![image-20211031153407979](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211031153407979.png)
存储结构
![image-20211031153002070](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211031153002070.png)
//线索二叉树存储结构
typedef struct TBTNode{
int data;
int lTag; //lTag=0,表示lChild为指针,指向结点左孩子,lTag=1,则表示lChild为线索,指向结点的直接前驱
int rTag; //rTag=0,表示rChild为指针,指向结点右孩子,rTag=1,则表示rChild为线索,指向结点的直接后继
TBTNode *lChild;
TBTNode *rChild;
}TBTNode;
二叉树中序线索化
void InThread(TBTNode *p,TBTNode *&pre){
if(p!=NULL){
InThread(p->lChild,pre); //递归,左子树线索化
if(p->lChild==NULL){ //建立当前结点的前驱线索
p->lChild=pre;
p->lTag=1;
}
if(pre!=NULL&&pre->rChild==NULL){ //建立前驱结点的后继线索
pre->rChild=p;
pre->tag=1;
}
pre=p; //pre指向当前的p,作为p将要指向下一个结点的前驱结点指示指针
InThread(p->rChild,pre); //递归,右子树线索化
}
}
前序线索二叉树
逻辑结构
![image-20211031160454371](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211031160454371.png)
存储结构
存储结构与中序线索二叉树的存储结构相同
二叉树前序线索化
void preThread(TBTNode *p,TBTNode *&pre){
if(p!=NULL){
if(p->lChild==NULL){ //建立当前结点的前驱线索
p->lChild=pre;
p->lTag=1;
}
if(pre!=NULL&&pre->rChild==NULL){ //建立前驱结点的后继线索
pre->rChild=p;
pre->tag=1;
}
pre=p;
if(p->lTag==0){
preThread(p->lChild,pre);
}
if(p->rTag==0){
preThread(p->rChild,pre);
}
}
}
前序线索二叉树执行遍历
void preorder(TBTNode *root){
if(root!=NULL){
TBTNode *p=root;
while(p!=NULL){
while(p->lTag==0){ //左指针不是线索,则边访问边左移
Visit(p);
p=p->lChild;
}
Visit(p); //此时左指针必定为线索,但还没有被访问,则访问
p=p->rChild; //此时p左孩子不存在,则右指针若非空,则不论是否为线索都指向其后继
}
}
}
后序线索二叉树
逻辑结构
![image-20211031162448838](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211031162448838.png)
存储结构
存储结构与中序线索二叉树的存储结构相同
二叉树后序线索化
void postThread(TBTNode *p,TBTNode *&pre){
if(p!=NULL){
postThread(p->lChild,pre); //递归,左子树线索化
postThread(p->rChild,pre); //递归,右子树线索化
if(p->lChild==NULL){ //建立当前结点的前驱线索
p->lChild=pre;
p->lTag=1;
}
if(pre!=NULL&&pre->rChild==NULL){ //建立前驱结点的后继线索
pre->rChild=p;
pre->tag=1;
}
pre=p;
}
}
*若结点X是二叉树的根,则其后继为空;
*若结点X是其双亲的右孩子,或是其双亲的左孩子且其双亲没有右子树,则其后继即为双亲节点;
*若结点X是其双亲的右孩子,且其双亲有右子树,则其后继为双亲右子树上按后序遍历列出的第一个结点;
三种线索二叉树的比较
![image-20211031180402172](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211031180402172.png)
**前序线索二叉树:**找后继方便,找某些结点的前驱不方便;
**中序线索二叉树:**找后继方便,找前驱方便;
**后序线索二叉树:**找后继不方便,找前驱不方便
树与二叉树的互相转换
树转换为“二叉树”(非严格意义上的二叉树,只是长得像)
![image-20211030203218397](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030203218397.png)
![image-20211030203242595](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030203242595.png)
![image-20211030203251517](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030203251517.png)
二叉树转换为树
![image-20211030203251517](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030203251518.png)
![image-20211030204109026](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030204109026.png)
![image-20211030203556452](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030203556452.png)
![image-20211030204145322](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211030204145322.png)
森林与二叉树的互相转换
森林转换为二叉树
1.
2.
3.
二叉树转换为森林
1.
2.
3.
哈夫曼树
利用编码问题理解哈夫曼树
![image-20211101212557241](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101212557241.png)
![image-20211101212822157](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101212822157.png)
![image-20211101212834427](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101212834427.png)
![image-20211101213146099](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101213146099.png)
![image-20211101213432557](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101213432557.png)
哈夫曼树中的基本定义
**路径:**路径是指从树中一个结点到另一个结点的分支所构成的路线;
**路径长度:**路径长度是指路径上的分支数目;
**树的路径长度:**树的路径长度是指从根到每个结点的路径长度之和;
**带权路径长度:**结点具有权值,从该结点到根之间的路径长度乘以结点的权值,就是该结点的带权路径长度;
(例如:E的带权路径长度=4*2=8)
**树的带权路径长度(WPL):**树的带权路径长度是指树中所有叶子结点的带权路径长度之和;
(例如:WPL=1X5+3X2+2X3+2X4+1X4=29)
哈夫曼二叉树的特点
*****权值越大的结点,距离根结点越近;
*****树中没有度为1的节点。这类树又叫做正则(严格)二叉树;
*****树的带权路径长度最短;
哈夫曼n(n大于2)叉树
哈夫曼三叉树的构造
![image-20211101214443695](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101214443695.png)
当剩余结点不够三个时我们可以补一个权值为0的结点以便构建哈夫曼三叉树
![image-20211101214635986](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101214635986.png)
二叉树的确定
已知先序和中序
逻辑推断
先序:A B D E C F G H 中序:D B E A C G F H
1.根结点为A,B D E为左子树 ,C G F H为右子树;
2.左子树根为B,右子树根为C(根据后序序列从左子树范围和右子树范围内找到的最靠前的那个结点);
3.B的左子树为D,右子树为E;
4.C的没有左子树,只有右子树且右子树的结点范围在(G F H)中;
5.G F H中以F为根,则C的右子树是F;
6.F的左子树为G,右子树为H;
推出下图:
![image-20211101220038891](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101220038891.png)
代码实现
BTNode *CreateBT(char pre[],char in[],int L1,int R1,int L2,int R2){
if(L1>R1)
return NULL;
BTNode *s=(BTNode *)malloc(sizeof(BTNode));
s->lChild = s->rChild = NULL;
s->data = pre[L1]; //L1为当前子树的根结点
int i;
for(i=L2;i<=R2;++i){ //从中序序列中寻找当前字数根结点的位置
if(in[i]==pre[L1]){
break;
}
}
s->lChild = CreateBT(pre,in,L1+1,L1+i-L2,L2,i-1);
s->rChild = CreateBT(pre,in,L1+i-L2+1,R1,i+1,R2);
return s;
}
![image-20211101221102795](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101221102795.png)
![image-20211101221225079](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101221225079.png)
已知后序和中序
逻辑推断
后序:D E B G H F C A 中序:D B E A C G F H
1.根结点为A,左子树结点范围 D B E,右子树结点范围 C G F H;
2.A的左子树根为B,右子树根为C(根据后序序列从左子树范围和右子树范围内找到的最靠后的那个结点);
3.B的左孩子为D,右孩子为E;
4.C没有左子树,只有右子树,右子树范围在(G F H)中;
5.G F H中以F为根,则C的右孩子是F;
6.F的左子树为G,右子树为H;
推出下图:
![image-20211101222108106](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101222108106.png)
代码实现
BTNode *CreateBT2(char post[],char in[],int L1,int R1,int L2,int R2){
if(L1>R1)
return NULL;
BTNode *s=(BTNode *)malloc(sizeof(BTNode));
s->lChild = s->rChild = NULL;
s->data = post[R1]; //R1为当前子树的根结点
int i;
for(i=L2;i<=R2;++i){ //从中序序列中寻找当前字数根结点的位置
if(in[i]==post[R1]){
break;
}
}
s->lChild = CreateBT2(post,in,L1,L1+i-L2-1,L2,i-1);
s->rChild = CreateBT2(post,in,L1+i-L2,R1-1,i+1,R2);
return s;
}
已知层次遍历序列和中序遍历序列
逻辑推断
层次:A B C D E F G H 中序:D B E A C G F H
1.A为根结点,左子树范围D B E,右子树范围C G F H;
2.B是左子树的根,C是右子树的根(根据层次遍历序列得到);
3.B的左子树为D,右子树为E;
4.C没有左子树,则C的右子树范围在G F H中;
5.F为C的右子树的根;
6.F的左子树为G,右子树为H;
推出下图:
![image-20211101222810216](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101222810216.png)
代码实现
int search(char arr[],char key,int L,int R){
int idx;
for(idx=L;idx<=R;++idx){
if(arr[idx]==key){
return idx;
}
}
return -1;
}
void getSubLevel(char subLevel[],char level[],char in[],int n,int L,int R){
int k=0;
for(int i=0;i<n;++i){
if(search(in,level[i],L,R)!=-1){
subLevel[k++]=level[i];
}
}
}
BTNode *CreateBT3(char level[],char in[],int n,int L,int R){
if(L>R)
return NULL;
BTNode *s=(BTNode *)malloc(sizeof(BTNode));
s->lChild = s->rChild = NULL;
s->data = level[0]; //level[0]为当前子树的根结点
int i = search(in,level[0],L,R); //从中序序列中查找根结点位置
int LN= i-L; char LLevel[LN]; //在左子树的范围中
int RN= R-i; char RLevel[RN];
getSubLevel(LLevel,level,in,n,L,i-1); //从level数组中挑出元素,如下图解
getSubLevel(RLevel,level,in,n,i+1,R);
s->lChild = CreateBT3(LLevel,in,LN,L,i-1);
s->rChild = CreateBT3(RLevel,in,RN,i+1,R);
return s;
}
![image-20211101223807992](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101223807992.png)
二叉树的估计和存储表达式
二叉树的估计
空树和只有根节点的树:
![](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101225133399.png)
![image-20211101225301050](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101225301051.png)
所有结点都没有左子树得树,即右单分支树
![image-20211101225342855](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101225342855.png)
![image-20211101225357368](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101225357368.png)
1.前序=后序的二叉树为:T L R L R T
2.前序=中序的二叉树为:T L R L T R
3.中序=后序的二叉树为:L T R L R T
4.前序和后序相反的二叉树为:T L R L R T
5.前序和中序相反的二叉树为:T L R L T R
6.中序和后序相反的二叉树为: L T R L R T
二叉树的存储表达式
![image-20211101230922638](https://gitee.com/chen_bo_27/cloundimage/raw/master/img/image-20211101230922638.png)
int calSub(float opand1,char op,float opand2,float &result){
if(op=='+') result = opand1 + opand2;
if(op=='-') result = opand1 - opand2;
if(op=='*') result = opand1 * opand2;
if(op=='/'){
if(fabs(opand2)<MIN)
return 0;
else
result = opand1/opand2;
}
return 1;
}
float cal(BTNode *root){
if(root->lChild == NULL&&root->rChild == NULL)
return root->data - '0';
else{
float opand1 = cal(root->lChild);
float opand2 = cal(root->rChild);
float result;
calSub(opand1,root->data,opand2,result);
return result;
}
}