155_2
05、已知一颗二叉树按顺序存储结构进行存储,设计一个算法,求编号分别为i和j的两个结点的最近的公共祖先结点的值
//求不同编号结点的最近的公共祖先结点的值
ElemType Comm_Ancestor(SqTree T,int i,int j)
{
if(T[i]!='#'&&T[j]!='#')//保证两个结点的值都不为空
{
while(i!=j)
{
if(i>j)
i/=2;//向上找i的祖先
else
j/=2;//向上找j的祖先
}//出while时 必然找到了公共祖先 i=j
}
return T[i];
}
5_3
03、试编写后序遍历二叉树的非递归算法
#include <stdio.h>
#define MaxSize 50
//树的存储结构
typedef struct BiTNode{
int data;//用字母表示数据域 如1 2 3 4等
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
//栈的存储结构
typedef struct{
BiTree data[MaxSize];//因为存储的是p 所以类型也应该为BiTree
int top;
}Bistack;
//初始化栈
void InitStack(Bistack &S)
{
S.top=-1;
}
//栈是否为空
bool IsEmpty(Bistack S)
{
if(S.top==-1)
return true;
else
return false;
}
//进栈
bool Push(Bistack &S,BiTree p)
{
if(S.top==MaxSize-1)
{
return false;
}
S.data[++S.top]=p;
return true;
}
//出栈
bool Pop(Bistack &S,BiTree &p)
{
if(S.top==-1)
{
return false;
}
p=S.data[S.top--];
return true;
}
//取栈顶元素
bool GetTop(Bistack S,BiTree &p)
{
if(S.top==-1)//栈空
{
return false;
}
p=S.data[S.top];
return true;
}
//二叉树后序非递归遍历
void PostTraverse_1(Bitree T)
{
InitStack(S);
BiTNode *p=T;
BiTNode *r=NULL;//用r来表示右子树是否被访问过
while(p||!StackEmpty(S))
{
if(p)
{
Push(S,p);//保存在栈中
p=p->lchild;//处理左子树
}else
{
GetTop(S,p);//取出栈顶元素 检查是否有右子树
if(p->rchild&&p->rchild!=r) //右子树存在且未被访问过
{
p=p->rchild;//处理其右子树
}else
{
Pop(S,p);//出栈 输出元素
printf("%d ",p->data);
r=p;//让r指向p 表示已被访问过
p=NULL;//每次访问过后将p置空
}
}
}
}
//测试
void test()
{
//Bistack S;
BiTNode a,b,c,d,e;
a.data=1;
a.lchild=&b;
a.rchild=&c;
b.data=2;
b.lchild=&d;
b.rchild=NULL;
c.data=3;
c.lchild=NULL;
c.rchild=NULL;
d.data=4;
d.lchild=NULL;
d.rchild=&e;
e.data=5;
e.lchild=NULL;
e.rchild=NULL;
BiTree T=&a;
PostOrder(T);
//输出应为5 4 2 3 1
}
int main()
{
test();
getchar();
return 0;
}
04、试给出二叉树的自下而上、从右到左的层次遍历算法
//倒序输出层次遍历
//思路:层序遍历 出队时 立即将结点压入栈中 最后让所有栈中元素出栈即可
void Inverse_LevelOrder(BiTree T)
{
Stack S,Queue Q;
if(T)//树不空
{
InitQueue(Q);InitStack(S);//分别将对列Q和栈S初始化
BiTNode *p=T;
Enqueue(Q,p);
while(!IsEmpty(Q))
{
Dequeue(Q,p);//对列保证先进先出 出队后立即压入栈中
Push(S,p);
if(p->lchild)
Enqueue(Q,p);//左子树不空 入队
if(p->rchild)
Enqueue(Q,p);//右子树不空 入队
}
while(!StackEmpty(S))//倒序输出
{
Pop(S,p);
printf("%d ",p->data);
}
}
}
05、假设二叉树采用二叉链表存储结构,设计一个非递归算法求二叉树的高度
//非递归算法求二叉树高度
//思路:采用层序遍历 设置一个标志last使其指向每层的最右边结点
int BTHeight(BiTree T)
{
int level=0,last=0;
int front=-1,rear=-1;//队列队头和队尾指针 初始为-1 指向空
BiTree Q[MAXSIZE];
if(!T)//树为空
return 0;
Q[++rear]=T;//将根结点入队
BiTNode *p;
while(front<rear)
{
p=Q[++front];//出队 即正在访问 的结点
if(p->lchild)
Q[++rear]=p->lchild;//左孩子入队
if(p->rchild)
Q[++rear]=p->rchild;//右孩子入队
if(front==last)//fornt与last相等表示 该层结点输出完毕
{
level++;//高度+1
last=rear;//让last指向下一层最右边结点
}
}
return level;
}
//递归求二叉树高度
int Btdepth(BiTree T)
{
int ldep,rdep;//分别代表左右子树高度
if(!T)
return 0;
ldep=Bedepth(T->lchild);//左子树高度
rdep=Bedepth(T->rchild);//右子树高度
if(ldep>rdep)
return ldep+1;//树的高度为子树最大高度+根结点
else
return rdep+1;
}
//求某层的结点个数
//非递归算法求二叉树高度
//思路:采用层序遍历 设置一个标志last使其指向每层的最右边结点
int BTHeight(BiTree T)
{
int s[MAXSIZE];//记录每层的结点个数
int cnt=0;
int level=0,last=0;
int front=-1,rear=-1;//队列队头和队尾指针 初始为-1 指向空
BiTree Q[MAXSIZE];
if(!T)//树为空
return 0;
Q[++rear]=T;//将根结点入队
BiTNode *p;
while(front<rear)
{
p=Q[++front];cnt++;//出队 即正在访问 的结点 出队即个数+1
if(p->lchild)
Q[++rear]=p->lchild;//左孩子入队
if(p->rchild)
Q[++rear]=p->rchild;//右孩子入队
if(front==last)//fornt与last相等表示 该层结点输出完毕
{
level++;//高度+1
s[level]=cnt;//记录完毕后 将cnt置0 方便重新计数
cnt=0;
last=rear;//让last指向下一层最右边结点
}
}
return level;
}
06、设一颗二叉树中各结点的值互不相同,其先序遍历序列和中序遍历序列分别存于两个一维数组A[1...n]和B[1..n]中,试编写算法建立该二叉树的二叉链表
//已知先序序列和中序序列建立二叉链表
//思路:递归
BiTree Create(ElemType A[],ElemType B[],int l1,int h1,int l2,int h2)
{//l1 h1分别代表先序序列的第一个和最后一个结点下标 l2 h2分别代表中序序列的第一个和最后一个结点下标
//初始调用时,l1=l2=1,h1=h2=n;
BiTNode *root=(BiTNode *)malloc(sizeof(BiTNode ));//建立根结点
root->data=A[l1];
for(i=l2;B[i]!=root->data;i++);//找到root结点在中序序列B[]中的位置i
llen=i-l2;//左子树长度
rlen=h2-i; //右子树长度
if(llen)//建立左子树
{
root->lchild=Create(A,B,l1+1,l1+llen,l2,l2+llen-1);
}
else
root->rchild=NULL;//左子树长度为0 则置为空
if(rlen)//建立右子树
{
root->rchild=Create(A,B,h1-rlen+1,h1,h2-rlen+1,h2);
}
else
root->rchild=NULL;//右子树长度为0 则置为空
return root;//返回根结点指针
}
07、二叉树按二叉链表形式存储,写一个判别给定二叉树是否是完全二叉树的算法
//7、判断是否是完全二叉树
//思路:采用层次遍历 将所有结点加入队列(包括空节点)
//遇到空节点时 查看其后是否有非空结点 若有则不是完全二叉树
bool IsComplete(BiTree T)
{
InitQueue(Q);
BiTNode *p;
if(!T)
return true;//空树也是完全二叉树
else
{
EnQueue(T);
while(!IsEmpty(Q))
{
DeQueue(Q,p);
if(p)//p不是空节点
{
EnQueue(Q,p->lchild);//将左子树入队
EnQueue(Q,p->rchild);//右子树入队
}else//遇到空节点 看队列中是否有非空结点
{
while(!IsEmpty(Q))
{
DeQueue(Q,p);
if(p)//有非空节点
return false;//不是完全二叉树
}
}
}
}
}
08、假设二叉树采用二叉链表存储结构存储,试设计一个算法,计算一颗给定二叉树的所有双分支结点个数
//计算双分支结点个数
//思路1;
//采用层次遍历 先将每个结点入队
//若对不空则出队 出队时判断该结点的左右孩子是否为空 若都不为空则cnt++
//思路2:
//递归:
//f(b)=0; 若b=NULL
//f(b)=f(b->lchild)+f(b->rchild)+1;//*b是双分支结点
//f(b)=f(b->lchild)+f(b->rchild); //*b为单分支结点或叶子结点
int DsonNodes(BiTree b)
{
if(b==NULL)
return 0;//空节点则返回0 也是递归出口
else if(b->lchild&&b->rchild)//左右孩子都存在
return DsonNodes(b->lchild)+DsonNodes(b->rchild)+1;
else
return DsonNodes(b->lchild)+DsonNodes(b->rchild);
}
09、设树B是一颗采用链式结构存储的二叉树,编写一个把树B中的所有结点的左、右子树进行交换的函数
//交换所有结点的左右子树
//思路:递归 将遍历算法中的visit()改为交换即可
void swap(BiTree T)
{
if(T)
{
swap(T->lchild);//递归交换左子树
swap(T->rchild);//递归交换右子树
BiTNode* temp=T->lchild;//交换左右孩子结点
T->lchild=T->rchild;
T->rchild=temp;
}
}
10、假设二叉树采用二叉链表存储结构存储,设计一个算法,求先序遍历序列中第k(1<=k<=二叉树中结点个数)个结点的值
//求先序遍历序列中第k个结点的值
//思路:
//设置一个全局变量num来表示先序遍历时当前访问的是第几个结点
//当num=k时 返回即可
int num=1;//注意num是全局变量
int k_thPreNode(BiTree b,int k)
{
if(b==NULL)
return '#';
if(num==k)
return b->data;
//不为空 也不是第k个结点 则num++ 访问下一个结点
num++;
int ch=k_thPreNode(b->lchild,k);
if(ch!='#')//ch不为'#' 才返回
return ch;
//ch为'#' 则继续
ch=k_thPreNode(b->rchild,k);
}
11、已知二叉树以二叉链表存储,编写算法完成:对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间。
//对于每个元素值为x的结点 删去以它为根的子树并释放相应空间
//思路:
//选择后序遍历删除以该结点为根的 子树 选择层次遍历找到该结点 删除 并将左右孩子结点置空
void DeleteXTree(BiTree &bt)
{
DeleteXTree(bt->lchild);
DeleteXTree(bt->rchild);//删除bt的左右子树
free(bt);//释放被删除结点所占的存储空间
}
//查找以x为元素值的结点,并删除以其为根的子树
void Search(BiTree bt,ElemeType x)
{
BiTree Q[max];//存放二叉树结点指针的队列 容量足够大
BiTree p;
if(bt)
{//bt不为空
if(bt->data==x)//根结点值为x 删除整棵树
{
DeleteXTree(bt);
exit(0);
}
}
InitQueue(Q);
EnQueue(Q,bt);
while(!IsEmpty(Q))
{
DeQueue(Q,p);
if(p->lchild)//左子树非空
{
if(p->lchild->data==x)//左子树是待删除结点
{
DeleteXTree(p->lchild);//删除
p->lchild=NULL;//左子树置空
}else//否则 入队
EnQueue(Q,p->lchild);
}
if(p->rchild)//右子树非空
{
if(p->rchild->data==x)//右子树是待删除结点
{
DeleteXTree(p->rchild);//删除
p->rchild=NULL;//右子树置空
}else//否则 入队
EnQueue(Q,p->rchild);
}
}
}
12、在二叉树中查找值为x的结点,试编写算法(用C语言)打印值为x的结点的所有祖先,,假设值为x的结点不多于1个。
//打印值为x的结点的所有祖先
//思路:后序非递归算法 特性:访问到值为x的结点时,栈中所有元素均为该结点的祖先,依次出栈打印即可
const int max=999;
typedef struct stack{
BiTree t;
int tag;//tag=0表示左子女被访问 tag=1表示右子女被访问
}stack;
void printXAnces(BiTree bt,ElemType x)
{
stack s[max];
int top=0;
while(bt!=NULL||top>0)
{
while(bt!=NULL&&bt->data!=x)
{
s[++top].t=bt;//入栈
s[top].tag=0;
bt=bt->lchild;//沿左分支向下
}
if(bt!=NULL&&bt->data==x)
{
printf("所查节点的祖先结点的值为:\n");
for(int i=1;i<=top;i++)//访问到x时 该结点还未入栈 故其祖先是此时栈中所有的结点 所以i<=top
printf("%d ",s[i].t->data);
exit(0);
}
while(top!=0&&s[top].tag==1)//退栈 空遍历
top--;
if(top!=0)
{
s[top].tag=1;
bt=s[top].t->rchild;//沿右分支向下遍历
}
}
}
13、
//找到任意两个结点的最近公共祖先
//思路:利用后序非递归遍历 访问到p时 栈中元素必是p的祖先 此时将栈复制到另一辅助栈中
//继续遍历到q时 将栈中元素从栈顶开始逐个到辅助栈中去匹配 第一个匹配的元素就是p和q的最近公共祖先
const int N=999;
typedef struct stack{
BiTree t;
int tag;//tag=0表示左子女被访问 tag=1表示右子女被访问
}stack;
stack s[N],s1[N];//栈 容量足够大
BiTree Ancestor(BiTree ROOT,BiTNode *p,BiTNode *q)
{
BiTree bt=ROOT;
int top=0,top1=0;
while(bt!=NULL||top>0)
{
while(bt!=NULL)
{
s[++top].t=bt;
s[top].tag=0;
bt=bt->lchild;//沿左分支向下
}
while(top!=0&&s[top].tag==1)
{
if(s[top].t==p)//访问到p 将栈中结点复制到s1
{
for(int i=1;i<=top;i++)
{
s1[i]=s[i];
top1=top;
}
}
if(s[top].t==q)
{//访问到q结点 将此时 栈中元素的树结点到s1中去匹配
for(int i=top;i>0;i--)//注意for循环的顺序
for(int j=top1;j>0;j--)
if(s1[j].t==s[i].t)
return s[i].t;
}
top--;//未访问到p q结点 出栈
}
if(top!=0)
{
s[top].tag=1;
bt=s[top].t->rchild;//沿右分支向下
}
}
return NULL;//p和q无公共祖先
}
14、假设二叉树采用二叉链表存储结构,设计一个算法,求非空二叉树b的宽度(即具有结点树最多的那一层的结点个数)
//14、求非空二叉树的宽度
//思路:采用层次遍历的方法求出所有节点的层次,并将所有节点和层次放在一个队列中
//扫描队列求出各层的结点总数 找出最大的即可
typedef struct{
BiTree data[MaxSize];
int level[MaxSize];
int front,rear;
}BiQueue;
int BTWidth(BiTree bt)
{
BiQueue Q;
Q.front=-1,Q.rear=-1;//队列指针初始化
int k,n,max,i;//k代表层数 n用于记录每层的结点树 max表示最大层节点数 即宽度
Q.rear++;
Q.data[Q.rear]=bt;//根结点入队
Q.level[Q.rear]=1;//根结点层次为1
while(Q.front<Q.rear)
{
Q.front++;
BiTree p=Q.data[Q.front];//出队
k=Q.level[Q.front];//出队结点的层次
if(p->lchild!=NULL)
{//左孩子存在
Q.data[++Q.rear]=p->lchild;//左孩子入队
Q.level[Q.rear]=k+1;//层次+1
}
if(p->rchild!=NULL)
{//右孩子存在
Q.data[++Q.rear]=p->rchild;//右孩子入队
Q.level[Q.rear]=k+1;//记录右孩子层次
}
}
//出while循环后 每层的节点数以及相应的层数 都已被记录
i=0,max=0;//i表示从入队的第一个元素开始向后扫描
k=1;//从第一层结点计数
while(i<=Q.rear)
{
n=0;
while(i<=Q.rear&&Q.level[i]==k)
{
n++;
i++;
}
//出while后 表示第k层结点已遍历完
//更新k
k=Q.level[i];
if(n>max) max=n;//记录最大的n
}
return max;
}
15、设有一颗满二叉树(所有节点值均不同),已知其先序序列为pre,设计一个算法求其后序序列post。
//15、将满树的先序序列转换为后序序列
//递归:
//先序序列的第一个结点一定是后序序列的最后一个结点
//由于是满树 取一半元素 先序除了根结点前一半一定是后序的前一半结点(左子树)
//同理 先序的后一半是后序的后一半 (右子树)
void PreToPost(ElemType pre[],int l1,int h1,ElemType post[],int l2,int h2)
{
int half;
if(h1>=l1)
{
post[h2]=pre[l1];
half=(h1-l1)/2;
PreToPost(pre,l1+1,l1+half,post,l2,l2+half-1);//递归转换左子树
PreToPost(pre,l1+half+1,h1,post,l2+half,h2-1);//递归转换右子树
}
}
16、设计一个算法将二叉树的叶节点按从左到右的顺序连成一个单链表,表头指针为head,二叉树按二叉链表方式存储,链接时用叶节点的右指针域来存当放单链表指针。
//16、将二叉树的叶节点从左到右链成一个单链表 用叶节点的右指针存放单链表指针
//思路:选择一种遍历方式 将访问操作改成链接操作
BiTree head,pre=NULL;
LinkList InOrder(BiTree bt)
{
if(bt)
{
InOrder(bt->lchild);
if(bt->lchild==NULL&&bt->rchild==NULL)
{
if(pre==NULL)//第一个叶结点
{
head=bt;
pre=bt;
}else
{
pre->rchild=head;
pre=bt;
}
}
InOrder(bt->rchild);
pre->rchild=NULL;//设置链表尾
}
return head;
}
17、试设计判断两棵二叉树是否相似的算法。所谓二叉树T1和T2相似,指的是T1和T2都是空的二叉树或都只有一个根结点;或T1的左子树和T2的左子是树相似的,且T1的右子树和T2的右子树是相似的。
//17、判断两颗二叉树相似
//递归
int resemble(BiTree T1,BiTree T2)
{
if(T1==NULL&&T2==NULL)
return 1;
if(T1==NULL||T2==NULL)//T1和T2只有一树为空 不相似
return 0;
int Left,Right;
Left=resemble(T1->lchild,T2->lchild);//递归 判断左子树
Right=resemble(T1->rchild,T2->rchild);//递归判断右子树
return Left&&Right; //当左右子树都相似时 才相似
}
18、写出在中序线索二叉树里查找指定结点在后序的前驱结点算法。
//18、中序线索二叉树中找指定结点在后序的前驱结点算法
//思路:在后序序列中 若结点p有右子女 则右子女是其前驱 若无右子女而有左子女 则其左子女是前驱
//若左右子女皆不存在 设其中序左线索指向某祖先结点f(f是p右子树中按中序遍历的第一个节点)
//若f有左子女 则其左子女是结点p在后序下的前驱;若f无左子女 则顺其前驱找双亲的双亲
//一直找到双亲有左子女(这时左子女是p的前驱)
//若p是总序遍历的第一个结点 则结点p在中序和后序下均无前驱
//线索二叉树的存储结构
typedef struct ThreadNode {
ElemType data;
struct ThreadNode* lchild, * rchild;
int ltag, rtag;//左右线索 标志
}ThreadNode, * ThreadTree;
ThreadNode* InPostPre(ThreadTree T,ThreadNode* p)
{
ThreadNode* q;
if(p->rtag==0)//右子树存在
q=p->rchild;
else if(p->ltag==0)//右子树不存在 左子树存在
q=p->lchild;
else if(p->lchild==NULL)//p是中序遍历下的第一个结点
q=NULL;//没有前驱
else
{
//顺着线索找到有左子树的双亲
while(p->ltag==1&&p->lchild!=NULL)
p=p->lchild;
if(p->ltag==0)
q=p->lchild;//左子树为后序前驱
else//否则 是单支树 没有后序前驱
q=NULL;
}
return q;
}
19、
//19、计算二叉树的带权路径长度
//思路:用层次遍历二叉树 同时记录当前层次
typedef struct BiTree{
BiTree lchild,rchild;//孩子指针
int weight;//权值
}BiTree;
typedef struct BiQueue{
BiTree data[Max];
int rear,front;
int level[MaxSize];
}BiQueue;
//计算wpl
int WPL(BiTree bt)
{
BiQueue Q;
BiTree p;
int k;//表示结点层次
Q.rear=Q.front=-1;//队列初始化
Q.rear++;
Q.data[Q.rear]=bt;
Q.level[Q.rear]=1;//根结点是第一层
while(Q.front<Q.rear)
{
p=Q.data[++Q.front];//出队
k=Q.level[Q.front];//记录结点层数
if(p->lchild!=NULL)
{
Q.data[++Q.rear]=p->lchild;
Q.level[Q.rear]=k+1;
}
if(p->rchild!=NULL)
{
Q.data[++Q.rear]=p->rchild;
Q.level[Q.rear]=k+1;
}
}
int Rec=Q.level[Q.rear];//记录二叉树总共的层数
//while循环结束时 则将所有的结点和相应层次都保存了
int sum=0;
int i=0;
for(k=1;k<=Rec;k++)
{
while(i<=Q.rear&&Q.level[Q.rear]==k)
{//算每一层的wpl
sum+=Q.data[Q.rear].weight*(k-1);//边的条数为层数-1
i++;
}
}
return sum;
}
//以上解法 是计算所有结点的带权路径长度
//计算叶节点的带权路径长度
//解法一:基于先序遍历的算法
int WPL(BiTree root)
{
return wpl_PreOrder(root,0);
}
int wpl_PreOrder(BiTree root,int deep)
{
static int wpl=0;//静态变量 在程序执行的整个期间一直存在
if(root->lchild==NULL&&root->rchild==NULL)
wpl+=deep*root->weight;//若为叶节点则累积wpl
if(root->lchild!=NULL)//左子树存在 递归遍历左子树
wpl_PreOrder(root->lchild,deep+1);
if(root->rchild!=NULL)//右子树存在 递归遍历右子树
wpl_PreOrder(root->rchild,deep+1);
return wpl;
}
//解法二:基于层次遍历的解法
int wpl_LevelOrder(BiTree root)
{
BiTree q[MaxSize];
BiTree lastNode,newlatNode;//lastNode表示当前层的最后一个节点 newlastNode表示下一层的最后一个结点
lastNode=root,newlastNode=NULL;//lastNode初始化为根结点 newlastNode初始化为NULL
int end1,end2;//end2为队尾 end1为队头
end1=end2=0;
int wpl=0,deep=0;//初始化wpl 和 深度
q[end2++]=root;
while(end1!=end2)
{
BiTree p=q[end1++];
//当前结点是叶子结点 累积wpl
if(p->lchild==NULL&&p->rchild==NULL)
wpl+=deep*p.weight;
//存在左子树 入队
if(p->lchild!=NULL)
{
q[end2++]=p->lchild;
newlastNode=p->lchild;//修改newlastNode
}
//存在右子树 入队
if(p->rchild!=NULL)
{
q[end2++]=p->rchild;
newlastNode=p->rchild;
}
if(p==lastNode)
{//访问到当前层的最后一个结点
lastNode=newlastNode;//修改当前层的最后一个结点指向下一层最后一个节点
deep++;//深度+1
}
}
return wpl;
}
20、
//20、将给定二叉树转换为中缀表达式 用括号显示运算顺序
//修改中序遍历即可 注意:根结点和叶子结点不加括号
//而分支节点则要加括号
typedef struct node{
char data[10];//存储操作数 或 操作符
struct node *left,*right;
}BTree;
void BtreeToE(BTree *root)
{
BtreeToExp(root,1);
}
void BtreeToExp(BTree *root,int deep)
{
if(root==NULL)
return;
else if(root->left==NULL&&root->right==NULL)
printf("%s",root->data);//有疑问 如果是数组的话 确实用%s 但root->data 是调值 感觉是字符 用%c
else
{
if(deep>1) printf("(");//有子表达式 即分支结点 加一层括号
BtreeToExp(root->left,deep+1);//往下遍历时 深度+1
printf("%s",root->data);
BtreeToExp(root->right,deep+1);
if(deep>1) printf(")");
}
}
5_4
04、编程求以孩子兄弟表示法存储的森林的叶子结点数。
//求孩子-兄弟表示法的叶节点综述
//递归:
typedef struct node{
ElemType data;
struct node *fch,*nsib;//孩子指针 和 兄弟指针
}*Tree;
int Leaves(Tree T)
{
if(T==NULL)
return 0;
if(T->fch==NULL)//无孩子 则自身就是叶节点
return 1+Leaves(T->nsib);
if(T->fch!=NULL);//有孩子 则叶节点为孩子树上和兄弟树上之和
return Leaves(T->fch)+Leaves(T->nsib);
}
05、以孩子兄弟链表为存储结构,请设计递归算法求树的深度。
//求孩子兄弟链表表示的树高
//递归求树的高度都类似
//因为此时表示法的根结点没有右孩子 树高就是左子树树高+1
//由于第一个孩子的右子树和第一个孩子的高度是相同的 所以比较第一个孩子的左子树高度+1和右子树高度即可
int height(CSTree bt)//Child-Sibling Tree
{
int hc,hs;//孩子树高度 和 兄弟树高度
if(bt==NULL)
return 0;
else
{//高度取子女高度+1和兄弟子树高度的大者
hc=height(bt->firstchild);//第一子女树 高
hs=height(bt->nextsibling);//兄弟树高
if(hc+1>hs)
return hc+1;
else
return hs;
}
}
06、已知一颗树的层次序列及每个结点的度,编写算法构造此树的孩子-兄弟链表。
//设立一个辅助数组pointer[]存储新建树的各结点的地址
//再根据层次序列与每个结点的度 逐个链接结点
#define maxNodes 15
typedef struct CSNode{
CSNode *lchild,*rsibling;
ElemType data;
}CSNode;
void createCSTree_Degree(CSTree &T,DataType e[],int degree[],int n)
{//e[]存储层次遍历的序列 degree[]存储结点的度 n是结点个数
CSNode* pointer=new CSNode[maxNodes];
int i,j,d,k=0;
//将pointer[]初始化
for(i=0;i<n;i++)
{
pointer[i]->data=e[i];
pointer[i]->lchild=pointer[i]->rsibling=NULL;
}
for(i=0;i<n;i++)
{
d=degree[i];
if(d)
{
k++;//第一个"度"结点是左孩子
pointer[i]->lchild=pointer[k];
for(j=2;j<=d;j++)
{
k++;
pointer[k-1]->rsibling=pointer[k];//剩余"度"结点是右兄弟
}
}
}
T=pointer[0];//将第一个结点作为树根
delete [] pointer;
}