DS博客作业05--树
1.本周学习总结
1.思维导图
2.谈谈你对树结构的认识及学习体会。
1.关于树的学习上,从遍历最基础的开始,树的很多操作都要用到递归,而递归是一件让人很头疼的事,在遇到递归函数时,经常有点摸不着头脑;
2.而要学会树的相关操作,则需要从递归遍历开始一层层深入学习,齐次我觉得可能和递归以前没有学好也有关系,可以适当看一下慕课上关于递归的视频来补充这方面缺失的知识面;
3.树的代码方面因为用到递归所以减少了不少代码量;在哈夫曼树解决修理牧场问题时,很巧妙的可以用到优先队列来解决,很大解决建树麻烦的问题;
4.线索二叉树可以解决需要知道某个结点的前后结点的问题;
2.PTA实验作业
2.1.题目1:7-5 jmu-ds-输出二叉树每层节点 (22 分)
- 层次遍历树中所有节点。输出每层树节点。
2.1.1设计思路(伪代码)
- 整体思路:运用两个指针记住当前结点位置和每层的最后一个结点位置,以便于当当前结点等于层最后结点时,输出换行并输出下一层结点;而每层的结点都要通过队列依次存入并且依次输出。
这里主要讲解void LayerNode(BTree bt)函数(主功能函数),即输出每层的结点的函数。
void LayerNode(BTree bt)//输出层节点
定义layer等于1表示输出的层数
定义flag用于判断是否为第一层结点
定义一个BTree型的队列qtree,用于存放结点
定义tNode,node和lastNode指针分别用于存放遍历中途结点的孩子结点,此时遍历到的结点和下一层要的最够一个结点
node=lastNode=bt
if bt不为空 do
bt入队列
else do
输出NULL并返回
end if
while 队列qtree不为空 do
if flag=0 do
输出“1:”,并将flag置为1 //即只在第一次循环时输出1
end if
node取队列qtree的front
if node->rchild do
将node->rchild赋值给tNode
else if node->lchild do
将node->lchild赋值给tNode /*先判断右结点是为了保证下一层最后一个结点在右孩子结点,若不在,则再判断左孩子*/
end if
输出node->data
并将node的左右孩子入队 //实现层层的遍历
将node结点出队
if node=lastNode and 队列不为空 do
换行再输出++layer //即下面输出的是下一层结点
lastNode = tNode //将下一层最右边的孩子结点赋值给lastNode
end if
end while
2.1.2代码截图
2.1.3本题PTA提交列表说明。
- Q1:二叉树为空的情况漏考虑了;
- A1:只要在刚开始入队情况下加上判断队列为空的条件即可解决;
- Q2:有一点不空的情况得不到解决;
- A2:测试数据发现当每一层最后结点不在上一层最后结点的右结点,则答案会出现错误;解决方法是记录上一层每个结点最靠右边的结点,在要进入下一层结点遍历时赋值给lastNode即可;
2.2.题目2:7-6 修理牧场 (25 分)
2.2.1设计思路(伪代码)
- 整体思路:输入的数为木头最后锯成的片段,当每次要锯木头时,应当使木头的长度尽可能的短,即要使每次两个长度最小和次小长度的木头和合成一根木头,并再加入所有木头中判断,依次重复操作,即可实现最后每次相加起来所花费的价钱最少;上述操作和建哈夫曼树的过程一致,上网查阅资料后发现优先队列更加适用这一题。
定义一个整型变量sum用来计算花费,初始化sum为0
定义一个整型变量len用来存木有长度
定义整型变量x,y
建一个优先队列 //优先队列的特点是每次操作完后,队列中的元素总能按升序排列
输入n为木头数
for i=0 to n do
输入每段木头长度len
将len入队
end for
while 队列长度不为1 do //即在队列中只剩一个数时退出
取两次队列头依次赋值给x和y,并依次pop掉
sum=sum+x+y //加上每次锯木头所花的钱
将x+y入队
end while
输出sum
2.2.2代码截图
2.2.3本题PTA提交列表说明。
- Q1:老是出现编译错误;
- A1:优先队列中greater函数头文件用错,应当使functional头文件;
- Q2:出现运行时错误和答案错误的情况;
- A1:刚开始设置while的控制条件是队列不为空,而如果有数据,则队列不为空的情况根本不可能出现,队列中最后至少会有一个数,即将条件改为队列长度不为一即可;
优先队列说明:
priority_queue <int,vector<int>,greater<int> > wpl;
//不需要#include<vector>头文件
//注意后面两个“>”不要写在一起,“>>”是右移运算符
//greater定义优先队列中的元素为升序排列,如果要得到降序排列,将greater改成less就可以了
2.3.题目3:7-4 jmu-ds-二叉树叶子结点带权路径长度和 (25 分)
2.3.1设计思路(伪代码)
- 整体思路:递归遍历每个结点,碰到叶子结点计算wpl大小,算出最后总的wpl值
int CalculateWpl(BTree bt,int h) //计算叶子结点带权路径长度和
if bt为空 do
return 0
end if
if bt->lchild为空 and bt->rchild为空 do //叶子结点
return bt->data*h //bt->data要转化为整型
end if
return 递归左子树和右子树
2.3.2代码截图
2.3.3本题PTA提交列表说明。
- Q1:刚开始第一次提交,只能过树为空的情况;
- A1:调试发现在计算wpl函数中,我用指针传h,导致高度的过程中h只会递增,且不会回到上一层的值,导致算出来的wpl值过大;将指针形式的h改成普通形式即可。
3、阅读代码
3.1 题目:662. 二叉树最大宽度
3.2 解题思路
- 整体思路:采用双端队列,二叉树的层次遍历。每层遍历前,在队列中清除左右两边的null指针,再计算队列长度即为该层的宽度。
int widthOfBinaryTree(TreeNode* root)
定义整型变量ans用来记录层宽度,并初始化为0
定义一个双端队列dque
定义一个空指针tmp
if root ==NULL do
返回ans值
end if //即为空树的情况
否则root进队
while 队列不空 do
while 队列不空 and dque的队头为NULL do
将队头出队
end while
while 队列不空 and dque的对尾为NULL do
将队尾出队
end while
定义n存此时队列大小
将dque的size赋值给n
判断n和ans大小关系,将较大值赋给ans
if n=0 do /*即此时队列为空*/
break
end if
for i=0 to n do i++
取队列头赋值给tmp
队列头出队
tmp的左右结点进队 //注意:null指针的左右两个儿子均为null。
end for
end while
3.3 代码截图
3.4 学习体会
- 学习了关于双端队列deque用法,即可以对队列的头尾都可以进行插入删除操作的队列。
- 本题计算二叉树的最大宽度时要考虑到结点为空时此时依旧占有一个宽度的情况,所以计算时,是从队列最左边不是NULL位置开始到最右边不是NULL结束,即为该层的最大宽度;