树的代码2
1.交换左右子树
设树B是一棵采用二叉链表形式存储的二叉树,编写一个把树B 中所有结点的左、右子树进行交换的函数。(58)
void Swap(BiTree &B){
if(B!=NULL){//改写先序递归遍历
BiTNode *temp=B->lchild://定义 temp 辅助指针,辅助 B左右子树交换
B->lchild=B->rchild;
B->rchild=temp;
Swap(B->lchild);//递归处理左子树
Swap(B->rchild)://递归处理右子树
}
}
2.求二叉树x结点的层次序号
假设二叉树采用二叉链表存储结构,设计一个算法,求二叉树T中值为x的结点的层次号。(59)
void Search x level(BiTree T,int x,int level){
if(T!=NULL){//改写先序递归遍历
if(T->data==x)//判断所处理结点是否等于x
printf(“x所在层数为%d”,level)://若该结点等于x则打印其层数
Search x level(T->lchild,x,level+1)://递归遍历左子树时需让层数加1
Search x level(T->rchild,x,level+1)://递归遍历右子树时需让层数加1
}
}
void Func(BiTree T.int x){
Search x level(T,x,1)://初始时根所在层次为1
}
3.反转层次遍历算法
试写出二叉树的自下而上、从右到左的层次遍历算法。(61)
就是比正常层次遍历增加一个栈
让出队的序列先放入栈,待所有结点入栈后,输出栈,即可得到反转层次遍历序列
void ReverseLevelOrder(BiTree T){
Queue Q;//定义队列 Q
Stack S;//定义栈 S
InitQueue(Q);//初始化队列 Q
InitStack(S)://初始化栈 S
BiTNode *p=T;//定义遍历指针 p,初始时指向根结点
EnQueue(Q,p);//根结点入队
while(!IsEmpty(Q)){//队列不为空则继续循环
DeQueue(Q,p);//出队,并让p指向出队结点
Push(S,p);//将出队结点压入栈S中
if(p->lchild)//若出队结点有左孩子,则让其左孩子入队
EnQueue(O,p->lchild);
if(p->rchild)//若出队结点有右孩子,则让其右孩子入队
EnQueue(Q,p->rchild);
}
while(!lsEmpty(S)){//栈不为空则继续循环
Pop(S,p);//出栈,并让p指向出栈结点
printf“%d”,p->data);//打印出栈结点数据域中的数据
}
}
4.判定是否为完全二叉树
二叉树按二叉链表形式存储,写一个判别给定二叉树是否是完全二叉树(62)
int IsComplete(BiTree T)
if(T==NULL)//若此树为空树则是完全二叉树
return 1;
Queue Q;//定义一个队列 O
InitQueue(Q);//初始化队列 Q
BiTNode *p=T;//定义遍历指针 p,初始时指向根结点
EnQueue(Q,p);//让根结点入队
while(!IsEmpty(Q)){//队列不为空则需继续循环
DeQueue(Q,p);//出队并让p指向出队结点
if(p!=NULL){//若p不为空
EnQueue(Q,p->lchild);//让其左孩子入队(左孩子为空则入队NULL)
EnQueue(Q,p->rchild);//让其右孩子入队(右孩子为空则入队NULL)
}
else//若p指向空则需判断队列中还有无结点
while(!lsEmpty(Q)){//队列不为空则需继续循环
DeQueue(Q,p);//出队并让p指向出队结点
if(p!=NULL)//若后续还有结点则不是完全二叉树
return 0;
}
}
return 1://若队列中剩余数据都为 NULL 则证明是完全二叉树
}
5.删除值为x的结点为跟的子树
已知二叉树采用二叉链表形式存储,设计一个算法完成:对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间(63)
改写后序递归遍历和层序遍历
void DeleteTree(BiTree &T){
if(T!=NULL)!//改写后序递归遍历
DeleteTree(T->lchild)://逆归处理左子树
DeleteTree(T->rchild)://递归处理右子树
free(T);//释放结点空间
}
}
void SearchX(BiTree &T,int x){
if(T==NULL)//若为空树则直接结束函数
return;i
if(T->data==x){//若根结点元素值为x则调用 DeleteTree函数删除整棵树
DeleteTree(T);
return;//函数执行结束
}
Queue Q://定义队列 O
InitQueue(O);//初始化队列 Q
BiTNode *p=T;//定义遍历指针 p,初始时指向根结点
EnQueue(Q,p);//根结点入队
while(!lsEmpty(Q)){//若队列不为空则需继续循环
DeQueue(Q,p);//出队并让p指向出队结点
if(p->lchild)//若出队结点有左孩子则判断其数据域数据是否等于x
if(p->lchild->data==x){//若等于则删除此结点左孩子为根的子树
DeleteTree(p->lchild);
p->lchild=NULL://让此结点左指针域置空
}
else{若此结点左孩子不等于x则入队
EnQueue(Q,p->lchild);
if(p->rchild)//若出队结点有右孩子则判断其数据域数据是否等于x
if(p->rchild->data==x){//若等于则删除此结点右孩子为根的子树
DeleteTree(p->rchild);
p->rchild=NULL;//让此结点右指针域置空
}
else
EnQueue(Q,p->rchild);//若此结点右孩子不等于x则入队
}
}
6.非递归算法计算二叉树高度
二叉树采用二叉链表存储结构,设计一个非递归算法求二叉树的高度。(64)
复杂改写二叉树层次遍历
int Depth(BiTree T){
if(T==NULL)//若树为空树则直接返回 0
return 0;
int h=0,last=0;//变量h用来记录高度,last 用来记录每一层最右边结点位置
BiTNode *O[MaxSizel;//定义队列 O
int font=-1,rear=-1;//定义队头指针和队尾指针
BiTNode *p=T;//定义遍历指针 p,初始时指向根结点
Q[++rear]=p;//根结点入队
while(front<rear){//队列不为空则继续循环
p=Q[++front];//出队,p指向出队结点
if(p->lchild)//若此结点有左孩子则让其左孩子入队
Q[++rear]=p->lchild;
if(p->rchild)//若此结点有右孩子则让其右孩子入队
Q[++rear]=p->rchild;
if(font==last){//若二叉树其中一层的最右边结点出队
h++://让高度加一
last=rear;//更新 last,使其指向下一层最右边结点位置
}
}
return h://返回二叉树的高度
}
7.二叉树的宽度
假设二叉树采用二叉链表存储结构,设计一个算法,求给定的二叉树的宽度。(宽度即树中具有结点数最多那一层的结点个数(65)
int Width(BiTree T){
if(T==NULL)//若为空树则宽度为0
retumn 0;
BiTNode *Q[MaxSizel;//定义队列O
int front=0,rear=0://定义队头指针和队尾指针
int level[MaxSizel;//定义存储结点层数的数组
BiTNode*p=T//定义遍历指针 p,初始时指向根结点
int k=1;/定义变量k记录指针p指向结点所在的层数
Q[rear]=p;//根结点入队
level[rear]=k,//记录根结点所在层数为1
rear++;//尾指针后移
while(font<rear){/若队列不为空则需继续循环
p=Q[front]//出队并让p指向出队结点
k=level[font];/更新k为出队结点所在层数
front++;/头指针后移
if(p->lchild){//若出队结点有左孩子
Q[rear]=p->lchild;/将该结点左孩子入队
level[rear]=k+l;/新入队结点所在层数为 k+1
rear++;//尾指针后移
}
if(p->rchild){/若出队结点有右孩子
Q[rear]=p->rchild//将该结点右孩子入队
level[rear]=k+l;/新入队结点所在层数为 k+1
rear++;/尾指针后移
}
}
int max=0,0,n;//定义 max 记录宽度,i作为遍历索引,n记录每一层结点数
k=1://k 用来表示所计数的是第几层,初始时等于1表示计数第一层
while(i<rear){//遍历记录结点层数的数组
n=0;/对每一层结点计数时都需初始化变量n
while(i<rear&&level[i]==k){//对第k层结点进行计数
n++;
i++;
}
k++;//本层计数结束,更新变量k,准备对下一层结点计数
if(m>max)//判断此层结点数是否为当前遍历过的最大宽度
max=n;
}
return max;//返回此树的宽度
}
8.输出值为x结点的祖先
在二叉树中查找值为x的结点,试编写算法打印值为x的结点的所有祖先,假设值为x的结点不多于一个。(69)
void Func(BiTree T,int x){//改写后序非递归遍历
Stack S://定义栈 S
InitStack(S)://初始化栈 S
BiTNode *p=T,*r=NULL://定义遍历指针 p 和记录指针r
while(p||!IsEmpty(S)){//若p不为空或栈不为空则继续循环
if(p!=NULL){//若p不为空则压栈,p指向该结点左子树
Push(S,p);
p=p->lchild;
}
else{
GetTop(S,p);//p 指向栈顶结点但不出栈
if(p->rchild&&p->rchild!=r)//若该结点有右子树且未被访问
p=p->rchild;//p 指向其右子树
else{//若该结点无右子树或者右子树已经被访问
Pop(S,p);//出栈并让p指向出栈结点
if(p->data==x)//判断其数据域中数据是否等于x
while(!IsEmpty(S)){//若等于x则打印栈中所有结点
Pop(S,p);//出栈并让p指向出栈结点
printf(“%d”,p->data);//打印结点数据
}
r=p;//更新记录指针位置
p=NULL;//将指针p置空进行下一次循环判断
}
}
}
}
9.找到两个结点最近公共祖先
p和q分别为指向一棵二叉树中任意两个结点的指针,试编写算法找到p和q最近公共结点并返回。
BiTNode *FindAncestor(BiTree T,BiTNode *p,BiTNode *q){//改写后序非递归遍历
BiTNode *bt=T,*F=NULL://定义遍历指针 bt 和记录指针r
BiTNode *S[MaxSize],*Sl[MaxSize],*$2[MaxSize];//定义三个栈S,S1,S2
int top=-1,topl=-1,top2=-1://定义三个栈顶指针
int temp;//定义辅助变量 temp
while(bt!=NULLltop!=-1){//若 bt 不为空或栈S不为空则需进行循环
if(bt!=NULL){//若 bt 不为空
S[++top]=bt;//根入栈
bt=bt->lchild;//bt 遍历该结点左子树
}
else{//若 bt 为空
bt=S[top];//bt 指向栈顶结点但不出栈
if(bt->rchild&&bt->rchild!=r)//若该结点有右孩子且未被访问
bt=bt->rchild;//bt 遍历该结点右子树
else{/若该结点没有右孩子或者右孩子已经被访问
bt=S[top--];//出栈并让 bt 指向出栈结点
if(bt==p){//判断如果该结点是p指向的结点则对其进行处理
for(temp=0;temp<=top,temp++)//栈S中结点即为p所有祖先
S1[temp]=S[temp]://将栈S中数据复制到栈 S1中
top1=top;//更新 S1 栈顶指针
}
if(bt==q){/判断如果该结点是q指向的结点则对其进行处理
for(temp=0;temp<=top;temp++)//栈S中结点即为q所有祖先
S2[temp]=S[temp];//将栈S 中数据复制到栈 S2中
top2=top;//更新 S2 栈顶指针
}
r=bt;//更新记录指针
bt=NULL;//bt 指针置空
}
}
}
for(int i=topl;i>=0;i--)//寻找栈 S1 和栈 S2 中最近公共结点
for(int j=top2;j>=0;j--)
if(S1[i]==S2[j])
retum S[i];//若找到即返回指向最近公共结点的指针变量
return NULL;//若未找到则返回 NULL
}
10.根到叶子的路径
假设一棵二叉树以二叉链表存储方式存储,请设计一个算法,输出根结点到每个叶子结点的路径。(71)
void AlPath(BiTree T){//改写后序非递归遍历
BiTNode *p=T,*r=NULL;//定义遍历指针 p,记录指针r
BiTNode *S[MaxSizel;//定义栈 S
int top=-1;//定义栈顶指针
while(p!=NULLlltop!=-1){//若p不为空或栈不为空则继续循环
if(p!=NULL){
S[++top]=p;//让p所指结点入栈
p=p->lchild;//p 遍历其左子树
}
else{
p=S[top];//p 指向栈顶结点但不出栈
if(p->rchild&&p->rchild!=r)//若p所指结点有右子树且未被访问
p=p->rchild://p 遍历其右子树
else{//若p所指结点无右子树或其右子树已被访问
p=S[top--];//出栈,并让p指向其出栈结点
if(p->lchild=-NULL&&p->rchild=-NULL){//若结点为叶子结点
for(int i=0;i<=top;i++)//打印栈中所有结点数据
printf(“%d”,S [i]->data);
printf(“%d”,p->data);//打印此叶子结点数据
r=p;//更新记录指针r
p=NULL;//将p指针置空
}
}
}
}
11.叶子结点顺序链接
设计一个算法将二叉树的叶子结点按从左到右的顺序连成一个单链表,表头指针为 head。二叉树按二叉链表方式存储,链接时用叶子结点的右指针域来存放单链表指针。(72)
BiTNode *head=NULL,*pre=NULL;//定义头指针 head 和记录指针 pre
void Link(BiTree &T){
if(T!=NULL){//改写中序递归遍历算法
Link(T->lchild);//递归遍历左子树
if(T->lchild==NULL&&T->rchild==NULL){/若此结点为叶子结点
if(pre==NULL){//判断此结点是否为访问到的第一个叶子结点
head=T://若为第一个叶子结点则让头指针 head 指向它
pre=T;//pre 负责记录上一次处理的叶子结点,所以进行更新
}
else{//若此结点不是第一个叶子结点
pre->rchild=T;//直接让上一个访问的叶子结点指向此结点
pre=T;//更新 pre 指针位置
}
}
Link(T->rchild);//递归遍历右子树
}
}