二叉树的存储结构
顺序存储
定义
#define MaxSize 100
struct TreeNode{
ElemType value; //节点中的数据元素
bool isEmpty; //节点是否为空
};
初始化
bool InitTreeNode(TreeNode &T[]){
int i;
for(i=0;i<MaxSize;i++){
T[i].isEmpty=true;
}
if(i==MaxSize+1)
return true;
else
return false; //初始化失败
}
链式存储
struct ElemType{
int value;
};
typedef struct BiTNode{
ElemType data; //值域
struct BitNode *lchild,*rchild; //指针域
}BiTNode,*BiTree;
void test(){
BiTree root=NULL; //定义一棵空树
//插入空节点
root=(BiTNode *)malloc(sizeof(BiTNode));
root.data={1};
root->lchild=NULL;
root->rchild=NULL;
}
n个节点的二叉链表共有n+1个空链域
分析:n个节点有2n个指针,使用了n-1个(根节点没有,其他都有一个),还剩n+1个。
二叉树的遍历
先序遍历
过程:
1.若二叉树为空,则什么也不做
2.若二叉树非空:先访问根节点–>先序遍历左子树—>先序遍历右子树(利用递归特性)
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode,* BiTree;
//先序遍历
void PreOrder(BiTree T){
if(T!=NULL){
visit(T); //访问当前根节点
PreOrder(T->lchild); //递归访问左子树
PreOrder(T->rchild); //递归 访问右子树
}
}
中序遍历
过程:
1.若二叉树为空,则什么也不做
2.若二叉树非空:先序遍历左子树—>先访问根节点–>先序遍历右子树(利用递归特性)
//中序遍历
void InOrder(BiTree T){
if(T!=NULL){
InOrder(T->lchild);
visit(T);
Inorder(T->rchild);
}
}
后序遍历
过程:
1.若二叉树为空,则什么也不做
2.若二叉树非空:先序遍历左子树–>先序遍历右子树—>先访问根节点(利用递归特性)
//后序遍历
void PostOrder(BiTree T){
if(T!=NULL){
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
先序遍历–>前缀表达式
中序遍历–>中缀表达式(需要加界限符)
后序遍历–>后缀表达式
求树的深度
int treeDepth(BiTree T){
if(T==NULL){
return 0;
}else{
int l=treeDepth(T->lchild);
int r=treeDepth(T->rchild);
return l>r?l+1:r+1;
}
}
二叉树的层序遍历
思想:
1.初始化一个辅助队列
2.根节点入队
3.若队列非空,则队头节点出队,访问该节点,并将其左右孩子插入队尾(如果有)
//二叉树
typedef struct BiTNode{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
//链式队列节点
typedef struct LinkNode{
BitNode *data; //存指针而不是节点
struct LinkNode *next;
}LinkNode;
typedef struct{
LinkNode *front,*rear;
}LinkQueue;
//顺序遍历
void levelOrder(BiTree T){
LinkQueue Q; //创建一个队列
InitQueue(Q); //初始化
BiTree p;
EnQueue(Q,T); //根节点入队
while(!EmptyQueue(Q)){ //队列不空
//队头节点出队
DeQueue(Q,p);
//访问队头节点
visit(p);
if(p->lchild!=NULL){
EnQueue(Q,p->lchild);
}
if(p->rchild!=NULL){
EnQueue(Q,p->rchild);
}
}
}
由遍历序列得到二叉树
条件:确定唯一的二叉树
1.前序加中序遍历序列
2.后序加中序遍历序列
3.层序加中序遍历序列
线索二叉树
作用:方便从一个指定节点出发,找到其前驱,后继,方便遍历
存储结构:
1.在普通二叉树的基础上,增加两个标志位ltag,rtag;
2.ltag=1时,表示lchild指向前驱;ltag=0时,表示lchild指向左孩子
1.中序线索二叉树的构造
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wFGrg27A-1627293541628)(C:\Users\25720\Desktop\1.png)]
//用土方法找到中序前驱
//思路:进行一次中序遍历,从第一个中序遍历的结点开始(D),若当前访问节点是所需要找到节点,则pre是中序前驱,否则将pre=当前节点
void InOrder(BiTree T){
if(T!=NULL){
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
//找p的前驱节点
void visit(BiTNode *q){
if(q==p){ //若当前节点是所需要的节点,则pre是前驱节点
final=pre;
}
else //若不是,则将pre=p,继续遍历
{
pre=p;
}
}
//辅助全局变量
BitNode *p; //需要查找前驱节点的节点
BiTNode *final=NULL; //结果
BiTNode * pre=NULL; //当前节点的前驱节点,初始为NULL;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fpj8YzmW-1627293541636)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722153456317.png)]
//中序线索二叉树的构造
//定义线索二叉树
typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag; //左右线索标志,0表示指向左右孩子,1表示指向线索
}ThreadNode,*ThreadTree;
Thread *pre=NULL; //全局变量,指向当前访问节点的前驱
//中序遍历二叉树,一边遍历一边线索化
void InThread(ThreadTree T){
if(T!=NULL){
InThread(T->lchild);
visit(T); //进行线索化
InThread(T->rchild);
}
}
void visit(ThreadNode *p){
//思路:当前节点若没有左孩子,则左指针指向pre,若当前pre不为空且pre的右指针为空,则pre的右指针指向p,pre是q的前驱
if(p->lchild==NULL){
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL && pre->rchild==NULL){
pre->rchild=p;
pre->rtag=1;
}
pre=p; //pre后移
}
void CreateThread(ThreadTree T){
//判断是否为空
if(T!=NULL){
//线索化
InThread(T);
if(pre->rchild==NULL){
pre->rtag=1;//最后一个节点访问之后,pre=p,且pre指向NULL,需要进行线索化(pre->rtag=1)
}
}
}
2.前序线索二叉树的构造
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m240PaeF-1627293541639)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722155619407.png)]
//需要注意的问题是进行左子树遍历时,要进行判断是否指向线索前驱
//改正后的代码为:
void PreThread(ThreadTree T){
if(T!=NULL){
visit(T); //先处理根节点
if(T->ltag==0)
PreThread(T->lchild);
PreThread(T->rchild);
}
}
中序线索二叉树找前驱后继
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rsHFAkGo-1627293541642)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722162359603.png)]
/*
分析:
要找节点p的后继,首先判断节点p的rtag是否为1,若为1,则p->rchild就是线索后继
若不为1,则以p为根节点的右子树的最左下的节点为后继
*/
//找到以p节点为根节点的子树中,最先被中序遍历访问的节点--->最左下的节点
ThreadNode *FirstNode(ThreadNode *p){
while(p->ltag==0) p=p->lchild;
}
//找p节点的后继节点
ThreadNode *NextNode(ThreadNode *p){
if(p->rtag==0) return FirstNode(p->rchild);
else return p->rchild;
}
//进行中序线索二叉树的遍历
void InoOrder(ThreadNode *T){
//从根节点开始,首先找到中序遍历最先被访问的节点,然后找后继一直访问
for(ThreadNode *q=FirstNode(T);q!=NULL;q=NextNode(q)){
visit(p);
}
}
找前驱
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6RLTqq2u-1627293541645)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722163617755.png)]
先序线索二叉树找前驱后继
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-diuTInuy-1627293541647)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722163953370.png)]
找先序后继
ThreadNode *NextPreNode(ThreadNode *p){
if(p->rtag==0){ //有右孩子
if(p->ltag==0) return p->lchild; //有左孩子
else return p->rchild;
}else
{
return p->rchild;
}
}
找先序前驱
p->ltag==1时,就是p->lchild;
p->ltag==0时,找不到,因为p的所有孩子只能是后继
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PnkcPIA4-1627293541649)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722165440562.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BMWztcwZ-1627293541651)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722165408248.png)]
后序线索二叉树找前驱后继
找前驱
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0XPQnlmC-1627293541654)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722165645491.png)]
void PrePostNode(ThreadNode *p){
if(p->ltag==0){
//如果有右孩子
if(p->rtag==0) return p->rchild;
else return p->lchild;
}
else{
return p-lchild;
}
}
找后继
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-USNz0H45-1627293541656)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722170336333.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-No0Iuxb4-1627293541657)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722170435813.png)]
总结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tFqVeqSn-1627293541659)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722170521408.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TQl5Cwps-1627293541662)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722170534756.png)]
前序后序二叉树可能的棵树问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YQt4D4jj-1627293541664)(C:\Users\25720\AppData\Roaming\Typora\typora-user-images\image-20210722204611644.png)]
做题
1,前序序列和中序序列的关系相当于以前序序列进栈,中序序列出栈
2.某二叉树的先序序列和后序序列正好相反,则该二叉树一定是高度等于其节点数