35.树与二叉树练习(1)(王道第5章综合练习)

【所用的树,队列,栈的基本操作详见上一节代码】

试题1(王道5.3.3节第3题):

编写后序遍历二叉树的非递归算法。

参考:34.二叉链树的C语言实现_北京地铁1号线的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_54708219/article/details/133581706

试题2(王道5.3.3节第4题):

给出二叉树自下而上,从右到左的层次遍历算法。

这道题很显然就是层次遍历算法调个个,加个栈即可实现:

//层次遍历(自下而上,从右到左)
void LevelOrder2(BiTree T){Queue q;InitQueue(q);Sqstack S;InitStack(S);BiTree p = T;InsertQueue(q, p);while(!IsQueueEmpty(q)){p = DeleteQueue(q, p);InsertSqstack(S, p);if(p->lchild!=NULL)InsertQueue(q, p->lchild);if(p->rchild!=NULL)InsertQueue(q, p->rchild);}while(S.top != -1){p = DeleteSqstack(S, p);printf("%c", p->data);}
}

输出:

输入二叉树的前序序列,#代表空子树:
ABD##E##C##
二叉树创建成功!
二叉树的层次遍历序列是:ABCDE
二叉树的层次遍历(自下而上,自右向左)序列是:EDCBA

试题3(王道5.3.3节第5题):

设计非递归算法求二叉树的高度。

此题采用层次遍历,附设一个指针a:

//利用层次遍历实现非递归计算树的深度
int LevelOrderDepth(BiTree T){int Depth = 0;if(!T)return Depth;else{Queue q;InitQueue(q);BiTree p = T;InsertQueue(q, p);Depth = 1;int a = q.rear;  //指针a指向队尾,也就是这一层最后一个元素while(!IsQueueEmpty(q)){if(q.front==a){  //这个时候说明这一层出完了,此时rear就是下一行的末尾结点a = q.rear;Depth = Depth + 1;}p = DeleteQueue(q, p);if(p->lchild!=NULL)InsertQueue(q, p->lchild);if(p->rchild!=NULL)InsertQueue(q, p->rchild);}return Depth;}
}

输出:

输入二叉树的前序序列,#代表空子树:
ABD##E##C##
二叉树创建成功!
二叉树的深度是(非递归算法):3

试题4(王道5.3.3节第6题):

设一棵二叉树中各结点的值互不相同,其先序遍历序列和中序遍历序列分别存放在两个数组A和B中,试编写算法建立该二叉树的二叉链表。

仍需要采用递归操作,这里要想办法根据前序序列找到根结点,然后在中序序列找根结点,从而确定哪些结点属于左子树,哪些结点属于右子树。

//由先序序列和中序序列建立二叉树
BiTree CreateBiTreeviaOrders(char a[],char b[],int x1,int y1,int x2,int y2){//x1,y1工作在前序序列中,x2,y2工作在中序序列中BiTree T;T = (BiTree)malloc(sizeof(BiTNode));T->data = a[x1];  //前序序列的第一个结点就是根结点int llen, rlen;for (int i = x2; i <= y2; i++){  //在中序序列找根结点if(b[i] == a[x1]){llen = i - x2;  //左子树的序列长度(结点个数)rlen = y2 - i;  //右子树的序列长度(结点个数)}}if (llen == 0)T->lchild = NULL;elseT->lchild = CreateBiTreeviaOrders(a, b, x1 + 1, x1 + llen, x2, x2 + llen - 1);if (rlen == 0)T->rchild = NULL;elseT->rchild = CreateBiTreeviaOrders(a, b, y1 - rlen + 1, y1, y2 - rlen + 1, y2);return T;
}int main(){BiTree T;char a[6] = {'A', 'B', 'C', 'D', 'E', 'F'};  //先序序列char b[6] = {'C', 'B', 'A', 'E', 'D', 'F'};  //中序序列T = CreateBiTreeviaOrders(a, b, 0, 5, 0, 5);  //初始必须是0和数组长度减一printf("该二叉树的后序遍历序列是:");PostOrderTraverse(T);  //输出后序序列进行验证return 0;
}

这里以王道5.3.3节单选15题进行验证,输出结果就是A选项。

该二叉树的后序遍历序列是:CBEFDA

试题5(王道5.3.3节第7题):

二叉树按二叉链表存储,写一个判别给定二叉树是否是完全二叉树的算法。

此题的思路是借助层次遍历和队列,当队列中输出空结点的时候,如果此时队列还有非空结点说明不是完全二叉树。注意这里输入和验证的都是扩展二叉树,所以去掉了层次遍历中的结点非空判断。

//判断是否是完全二叉树
bool IfCompleteTree(BiTree T){Queue q;InitQueue(q);BiTree p = T;if(!p)return true;InsertQueue(q, p);while(!IsQueueEmpty(q)){p = DeleteQueue(q, p);if(p!=NULL){InsertQueue(q, p->lchild);InsertQueue(q, p->rchild);}else{int a = q.front;while(a!=q.rear){if(q.data[a]!=NULL)return false;a = (a + 1) % MAXSIZE;}return true;}   }
}int main(){BiTree T;printf("输入二叉树的前序序列,#代表空子树:\n");CreateBiTree(T);printf("二叉树创建成功!\n");printf("该二叉树是否是完全二叉树?%d", IfCompleteTree(T));return 0;
}

输出:

输入二叉树的前序序列,#代表空子树:
ABD##E##C##
二叉树创建成功!
该二叉树是否是完全二叉树?1输入二叉树的前序序列,#代表空子树:
AB##CD##E##
二叉树创建成功!
该二叉树是否是完全二叉树?0

试题6(王道5.3.3节第8题):

设二叉树采用二叉链表存储结构,设计算法计算给定二叉树的双分支结点个数。

递归算法:

//判断是否是完全二叉树
int TwobranchNodes(BiTree T){if(T==NULL)return 0;else if(T->lchild!=NULL&&T->rchild!=NULL)return TwobranchNodes(T->lchild) + TwobranchNodes(T->rchild) + 1;elsereturn TwobranchNodes(T->lchild) + TwobranchNodes(T->rchild);
}

非递归算法(层次遍历逐个结点检查):

//判断是否是完全二叉树
int TwobranchNodes(BiTree T){int a = 0;Queue q;InitQueue(q);BiTree p = T;InsertQueue(q, p);while(!IsQueueEmpty(q)){p = DeleteQueue(q, p);if(p->lchild!=NULL && p->rchild!=NULL)a = a + 1;if(p->lchild!=NULL)InsertQueue(q, p->lchild);if(p->rchild!=NULL)InsertQueue(q, p->rchild);}return a;
}

试题7(王道5.3.3节第9题):

设树B是一棵采用链式结构存储的二叉树,编写一个把树B中所有结点的左右子树进行交换的函数。

此题同题6一样也可以用递归或层次遍历的方法,这里给出非递归的方法:

//把二叉树的左右子树交换
int ChangeTwobranch(BiTree &T){Queue q;InitQueue(q);BiTree p = T;BiTree r;InsertQueue(q, p);while(!IsQueueEmpty(q)){p = DeleteQueue(q, p);if(p->lchild!=NULL || p->rchild!=NULL){r = p->lchild;p->lchild = p->rchild;p->rchild = r;}if (p->lchild != NULL)InsertQueue(q, p->lchild);if(p->rchild!=NULL)InsertQueue(q, p->rchild);}return 0;
}

输出:

输入二叉树的前序序列,#代表空子树:
ABD##E##C##
二叉树创建成功!
该二叉树的层次遍历序列是:ACBED

试题8(王道5.3.3节第10题):

假设二叉树采用二叉链存储结构存储,设计算法求先序遍历序列中第k个结点的值。

这里使用一个计数器即可:

//输出前序遍历的第x个元素
void PreOrderx(BiTree T,int x){int a = 0;BiTree p = T; //p是遍历指针Sqstack S;InitStack(S);while(p != NULL|| !IsStackEmpty(S)){if(p){a = a + 1;if(a == x){printf("第%d个元素是:%c", x, p->data);break;}  InsertSqstack(S, p);p = p->lchild;}else{p = DeleteSqstack(S, p);p = p->rchild;}}
}

当然也可以采用递归,注意这里的计数器必须写在全局变量里,否则每次调用递归都会从零开始:

//输出前序遍历的第x个元素
int a = 0;  //计数器
void PreOrderx(BiTree T,int x){if (T!=NULL){a = a + 1;if(a==x)printf("前序遍历序列的第%d个元素是:%c", x, T->data);PreOrderx(T->lchild,x);PreOrderx(T->rchild,x);}
}int main(){BiTree T;printf("输入二叉树的前序序列,#代表空子树:\n");CreateBiTree(T);printf("二叉树创建成功!\n");PreOrderx(T, 3);return 0;
}

输出:

输入二叉树的前序序列,#代表空子树:
ABD##E##C##
二叉树创建成功!
前序遍历序列的第3个元素是:D

试题9(王道5.3.3节第11题):

已知二叉树以二叉链表存储,编写算法完成:对于树中的每个值为x的结点,删去以它为根的子树,并释放相应空间。

仍然是与层次遍历结合:

//这个函数用来删除树T
void Free(BiTree &T){if(T!=NULL){Free(T->lchild);Free(T->rchild);free(T);}
}//对值为x的结点,删除以它为根的子树
void Freex(BiTree &T,char x){Queue q;InitQueue(q);BiTree p = T;InsertQueue(q, p);while(!IsQueueEmpty(q)){p = DeleteQueue(q, p);if(p->data == x){Free(p->lchild);  //这样写保留了当前结点Free(p->rchild);p->lchild = NULL;p->rchild = NULL;}if(p->lchild!=NULL)InsertQueue(q, p->lchild);if(p->rchild!=NULL)InsertQueue(q, p->rchild);}
}int main(){BiTree T;printf("输入二叉树的前序序列,#代表空子树:\n");CreateBiTree(T);printf("二叉树创建成功!\n");printf("当前二叉树的层次遍历序列是:");LevelOrder(T);printf("\n");Freex(T, 'B');  //删除以B为根结点的树printf("当前二叉树的层次遍历序列是:");LevelOrder(T);printf("\n");return 0;
}

输出:

输入二叉树的前序序列,#代表空子树:
ABD##E##C##
二叉树创建成功!
当前二叉树的层次遍历序列是:ABCDE
当前二叉树的层次遍历序列是:ABC输入二叉树的前序序列,#代表空子树:
ABD###CE##F##
二叉树创建成功!
当前二叉树的层次遍历序列是:ABCDEF
当前二叉树的层次遍历序列是:ABCEF

试题10(王道数据结构5.3.3节第12题):

编写算法打印值为x的结点的所有祖先,假设值为x的结点不多于一个。

此题的算法十分典型:它用的是非递归后序遍历算法,这种算法需要借助栈来实现,当访问到值为x的结点的时候,栈中所有元素就是该结点的祖先,依次打印输出即可。有关非递归后序遍历算法的代码在上一节。

//寻找给定结点的所有祖先结点,采用后续遍历的非递归算法
void FindParents(BiTree T,char x){Sqstack S;InitStack(S);BiTree p = T;BiTree r = NULL;  //r用来记录访问结点的前一个结点while(p||!IsStackEmpty(S)){if(p){InsertSqstack(S, p);p = p->lchild;}else{p = S.data[S.top];  //读栈顶元素(但不出栈)if(p->rchild&&p->rchild!=r){p = p->rchild;}else{p = DeleteSqstack(S, p);if(p->data == x){printf("%c", p->data);break;}r = p;p = NULL;}}}while(!IsStackEmpty(S)){  //这个时候栈里的元素全部是结点的祖先p = DeleteSqstack(S, p);printf("%c", p->data);}
}int main(){BiTree T;printf("输入二叉树的前序序列,#代表空子树:\n");CreateBiTree(T);printf("二叉树创建成功!\n");printf("当前二叉树的层次遍历序列是:");LevelOrder(T);printf("\n");printf("当前二叉树中结点E的祖先结点是:");FindParents(T, 'E');return 0;
}

输出:

输入二叉树的前序序列,#代表空子树:
ABD##E##C##
二叉树创建成功!
当前二叉树的层次遍历序列是:ABCDE
当前二叉树中结点E的祖先结点是:EBA

试题11(王道数据结构5.3.3节第13题):

给出二叉链树中两个结点的指针p和q,试编写算法求解p和q的公共祖先结点r。

此题和上一题很像,分别求出p和q的祖先然后比较即可。

//寻找给定结点的所有祖先结点,采用后续遍历的非递归算法,和上一题不同的是,本题以栈的形式返回
Sqstack FindParents(BiTree T,char x){Sqstack S;InitStack(S);BiTree p = T;BiTree r = NULL;  //r用来记录访问结点的前一个结点while(p||!IsStackEmpty(S)){if(p){InsertSqstack(S, p);p = p->lchild;}else{p = S.data[S.top];  //读栈顶元素(但不出栈)if(p->rchild&&p->rchild!=r){p = p->rchild;}else{p = S.data[S.top];if(p->data == x){break;}p = DeleteSqstack(S, p);r = p;p = NULL;}}}return S;
}
//有了两个栈我们就可以遍历然后找到祖先结点了
//注意这里最差也能返回整棵二叉树的根结点,或者返回其中一个结点时,代表一个结点就是另一个结点的祖先
BiTree FindSameParents(BiTree T,char a,char b){Sqstack S1 = FindParents(T, a);Sqstack S2 = FindParents(T, b);int same = -1;  //same用来遍历两个栈,并指向最后一个相同的祖先结点while(S1.data[same+1] == S2.data[same+1]){same = same + 1;}printf("%c", S1.data[same]->data);return S1.data[same];
}int main(){BiTree T;printf("输入二叉树的前序序列,#代表空子树:\n");CreateBiTree(T);printf("二叉树创建成功!\n");printf("当前二叉树的层次遍历序列是:");LevelOrder(T);printf("\n");printf("当前二叉树中结点E,F的祖先结点是:");FindSameParents(T, 'E', 'F');  //求E,F的祖先结点return 0;
}

输出:

输入二叉树的前序序列,#代表空子树:
ABD###CE##F##
二叉树创建成功!
当前二叉树的层次遍历序列是:ABCDEF
当前二叉树中结点E,F的祖先结点是:C

试题12(王道数据结构5.3.3节第14题):

假设二叉树采用二叉链表存储,设计一个算法求非空二叉树的宽度(也就是结点数最多的那一层的结点个数)。

此题仍然可以利用层次遍历把每层的结点数输出,存在一个数组里面然后找出最大值:

//求非空二叉树的宽度,借助层次遍历把每层的结点数都求出来
int LevelOrderWidth(BiTree T){Queue q;InitQueue(q);BiTree p = T;InsertQueue(q, p);int a = q.front;  //a指针指向这一层的第一个结点int b = q.rear;  //b指针指向这一层的第一个结点int num = 1;     //输出这一层的结点个数int numarray[10];  //把各层的结点个数存在一个数组里int depth = 0;  //深度,实际深度是depth+1,因为numarray数组下标从0开始numarray[depth] = num;while(!IsQueueEmpty(q)){if(q.front == b){  //说明这一层出完了a = q.front;  //a指向下一层第一个结点b = q.rear;  //b指向下一层最后一个结点num = (b - a > 0) ? (b - a) : (b - a + MAXSIZE);  //循环队列三目运算符判断depth = depth + 1;numarray[depth] = num;}p = DeleteQueue(q, p);if(p->lchild!=NULL)InsertQueue(q, p->lchild);if(p->rchild!=NULL)InsertQueue(q, p->rchild);}//到此numarray存储了每层的结点数,接下来找其中的最大值输出num = 1;for (int i = 0; i <= depth;i++){printf("%d", numarray[i]);if(numarray[i] > num)num = numarray[i];}return num;
}int main(){BiTree T;printf("输入二叉树的前序序列,#代表空子树:\n");CreateBiTree(T);printf("二叉树创建成功!\n");printf("当前二叉树的层次遍历序列是:");LevelOrder(T);printf("\n");printf("各层的结点数是:");printf("二叉树的宽度是:%d",LevelOrderWidth(T));return 0;
}

输出:

输入二叉树的前序序列,#代表空子树:
ABDF##G##E##CH###
二叉树创建成功!
当前二叉树的层次遍历序列是:ABCDEHFG
各层的结点数是:1232二叉树的宽度是:3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/100149.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D 生成重建005-NeRF席卷3D的表达形式

3D生成重建005-NeRF席卷3D的表达形式 文章目录 0 论文工作1 论文方法1.1 体渲染1.2 离散积分1.3位置编码1.4分层采样1.5 影响 2 效果 0 论文工作 NeRF(神经辐射场技术)最早2020年提出用于新视图合成任务&#xff0c;并在这个领域取得了优秀的效果。如下图所示&#xff0c;受到…

Springcloud笔记(2)-Eureka服务注册

Eureka服务注册 服务注册&#xff0c;发现。 在Spring Cloud框架中&#xff0c;Eureka的核心作用是服务的注册和发现&#xff0c;并实现服务治理。 Eureka包含两个组件&#xff1a;Eureka Server和Eureka Client。 Eureka Server提供服务注册服务&#xff0c;各个节点启动后…

mysql面试题31:一条SQL语句在MySQL中如何执行的

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:一条SQL语句在MySQL中如何执行的 以下是一条SQL语句在MySQL中的详细执行步骤: 语法分析:MySQL首先对SQL语句进行语法分析,检查SQL语句是否符合…

ARM-流水灯

.text .global _start _start: 1、设置GPIOE寄存器的时钟使能 RCC_MP_AHB$ENSETR[4]->1 0x50000a28LDR R0,0X50000A28 LDR R1,[R0] 从R0起始地址的4字节数据取出放在R1 ORR R1,R1,#(0X3<<4) 第4位设置为1 STR R1,[R0] 写回2、设置PE10、PE8、PF10管脚为输出模式 …

elasticSearch7.9数据占用磁盘存储空间情况

最近&#xff0c;在VMware Workstation虚拟机上安装了es7.9&#xff0c;单节点的es&#xff0c;不是集群&#xff0c;然后建了一个索引&#xff08;包含3个分片和一个副本&#xff09;&#xff0c;插入了500万条数据&#xff0c;占据磁盘空间17G。如下图&#xff1a; 索引的字…

在两个有序数组中找整体第k小的数

一、题目 给定两个已经排序的数组&#xff08;假设按照升序排列&#xff09;&#xff0c;然后找出第K小的数。比如数组A {1&#xff0c; 8&#xff0c; 10&#xff0c; 20}&#xff0c; B {5&#xff0c; 9&#xff0c; 22&#xff0c; 110}&#xff0c; 第 3 小的数是 8.。…

基于Springboot实现点餐平台网站管理系统项目【项目源码+论文说明】分享

基于Springboot实现点餐平台网站管理系统演示 摘要 随着现在网络的快速发展&#xff0c;网上管理系统也逐渐快速发展起来&#xff0c;网上管理模式很快融入到了许多商家的之中&#xff0c;随之就产生了“点餐平台网站”&#xff0c;这样就让点餐平台网站更加方便简单。 对于本…

解决远程git服务器路径改变导致本地无法push的问题

解决远程git服务器路径改变导致本地无法push的问题 &#xff08;1&#xff09;第一步&#xff1a;查看git配置 git config -l&#xff08;2&#xff09;第二步&#xff1a;删除远程git地址 git remote remove origin&#xff08;3&#xff09;第三步&#xff1a;再次查看git配…

ELK 处理 SpringCloud 日志

在排查线上异常的过程中&#xff0c;查询日志总是必不可缺的一部分。现今大多采用的微服务架构&#xff0c;日志被分散在不同的机器上&#xff0c;使得日志的查询变得异常困难。工欲善其事&#xff0c;必先利其器。如果此时有一个统一的实时日志分析平台&#xff0c;那可谓是雪…

Mall脚手架总结(三) —— MongoDB存储浏览数据

前言 通过Elasticsearch整合章节的学习&#xff0c;我们了解SpringData框架以及相应的衍生查询的方式操作数据读写的语法。MongoDB的相关操作也同样是借助Spring Data框架&#xff0c;因此这篇文章的内容比较简单&#xff0c;重点还是弄清楚MongoDB的使用场景以及如何通过Sprin…

【计算机网络】UDP协议编写群聊天室----附代码

UDP构建服务器 x 预备知识 认识UDP协议 此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论. 传输层协议无连接不可靠传输面向数据报 网络字节序 我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的…

扬尘监测:智能化解决方案让生活更美好

随着工业化和城市化的快速发展&#xff0c;扬尘污染问题越来越受到人们的关注。扬尘不仅影响城市环境&#xff0c;还会对人们的健康造成威胁。为了解决这一问题&#xff0c;扬尘监测成为了一个重要的手段。本文将介绍扬尘监测的现状、重要性以及智能化解决方案&#xff0c;帮助…

Python库学习(九):Numpy[续篇三]:数组运算

NumPy是用于数值计算的强大工具&#xff0c;提供了许多数组运算和数学函数&#xff0c;允许你执行各种操作&#xff0c;包括基本运算、统计计算、线性代数、元素级操作等 1.基本运算 1.1 四则运算 NumPy数组支持基本的四则运算&#xff08;加法、减法、乘法和除法&#xff09;…

Flink学习笔记(一):Flink重要概念和原理

文章目录 1、Flink 介绍2、Flink 概述3、Flink 组件介绍3.1、Deploy 物理部署层3.2、Runtime 核心层3.3、API&Libraries 层3.4、扩展库 4、Flink 四大基石4.1、Checkpoint4.2、State4.3、Time4.4、Window 5、Flink 的应用场景5.1、Event-driven Applications【事件驱动】5.…

初识 C语言文件操作

目录 前言&#xff1a; 为什么我们要使用文件&#xff1f; 什么是文件&#xff1f; 程序文件&#xff1a; 数据文件&#xff1a; 文件名&#xff1a; 文件的打开和关闭 文件指针&#xff1a; 流程&#xff1a; 文件路径&#xff1a; 文件的顺序读写&#xff1a; …

【Java 进阶篇】CSS语法格式详解

在前端开发中&#xff0c;CSS&#xff08;层叠样式表&#xff09;用于控制网页的样式和布局。了解CSS的语法格式是学习如何设计和美化网页的关键。本文将深入解释CSS的语法格式&#xff0c;包括选择器、属性和值等基本概念&#xff0c;同时提供示例代码以帮助初学者更好地理解。…

首批成员单位 | 聚铭网络受邀加入中国人工智能产业发展联盟数据委员会

近日&#xff0c;中国人工智能产业发展联盟(简称AIIA&#xff09;成立“数据委员会”&#xff0c;**聚铭网络受邀加入&#xff0c;成为首批成员单位&#xff0c;**与其他成员单位协同推动人工智能产业发展。 中国人工智能产业发展联盟是在国家发展和改革委员会、科学技术部、工…

Python Opencv实践 - 车辆识别(1)读取视频,移除背景,做预处理

示例中的图像的腐蚀、膨胀和闭运算等需要根据具体视频进行实验得到最佳效果。代码仅供参考。 import cv2 as cv import numpy as np#读取视频文件 video cv.VideoCapture("../../SampleVideos/Traffic.mp4") FPS 10 DELAY int(1000 / FPS) kernel cv.getStructu…

VSCode Intellij IDEA CE 数据库连接

VSCode & Intellij IDEA CE 数据库连接 大概记一下现在正在用的几个工具/插件 VSCode VSCode 里面的工具我下载了很多&#xff0c;如果只是链接 MySQL 的话&#xff0c;可能用 Jun Han 这位大佬的 MySQL 就好了&#xff1a; 使用这个插件直接打开 .sql 文件单击运行就能…

制作电商页面(Html)

任务 制作一个电商页面&#xff0c;要求所卖物品清晰&#xff0c;页面色调清晰&#xff0c;要有主页和详情页。 网站所买物品&#xff1a;书籍 色调&#xff1a;#FF2400 橙红色 代码 主页HTML代码&#xff1a; <html><head><meta charset"utf-8"…