1.本周学习总结(0--2分)
1.思维导图
2.谈谈你对树结构的认识及学习体会。
不同类型的树之间是可以相互转化的,比如一颗普通的树可以通过特定的过程转化成二叉树,也可以转化成森林,反之亦然。
树也存在着多种的存储结构,例如:双亲存储,孩子链存储,孩子兄弟存储
二叉树是最常见的树,我们详细的学历了二叉树的创建、消除等等基本构造二叉树的方法,也学习了如何用先序加中序,中序加后序来进行树的构建。通过二叉树的学习,我们又学习了线索二叉树,和哈夫曼树,这两个知识点都是在二叉树的基础上进行升华的。
线索二叉树可以轻易的得到该结点的相邻的结点,而哈夫曼树则可以用来求解最优解的问题。
2.PTA实验作业(6分)
2.1.根据后序和中序遍历输出先序遍历
本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果。
2.1.1设计思路(伪代码)
以样例为例
//伪代码(BinTree CreatBt函数)
if n=0 then
return 0
end if
定义一个BinTree类型的变量BT//构造结点
定义一个int型变量mid//用于储存in数组中,该结点的位置
for i=0 to n do
if in[i]与post[n-1]相等 then
将i赋值给mid
break;
end if
end for
将post[n-1]的值赋给BT->data
BT->lchild =CreatBt(post,in,mid)//递归创建左孩子
BT->rchild =CreatBt(post+mid,in+1+mid,n-1-mid)//递归创建右孩子
2.1.2代码截图
2.1.3本题PTA提交列表说明。
Q1:一连串的编译错误……快把我搞疯掉
A1:然而,全都是一些基本的错误,比如把
Q2:其实,他提示的错误点,我没看懂
A2:然后,就到编译器上去调试了,结果才发现,我定义的变量mid没赋值,我也传参传的好好的。
2.2 jmu-ds-输出二叉树每层节点
层次遍历树中所有节点。输出每层树节点。
树结构按照树的先序遍历递归建树,比如先序遍历字符串“ABD#G###CEH###F#I##”#代表空节点。
2.2.1设计思路(伪代码)
//设计思路
利用队列,将二叉树按行存入队列中,利用flag,当flag为1时代表,curNode在该行的第一个位置,当flag=0时,依次出队输出,直到curNode与该行的队尾指针lastNode相等时,进入下一行的扫描。
//伪代码(LevelOrder函数)
定义BinTree型的队列qt
定义int型变量level并赋初值为0,用于表示行数;flag并赋初值为1,用于判断是否为每行开头
定义BinTree型变量curNode、lastNode//分别指向当点结点和该行的最后一个结点,并将bt赋值给两个变量
if bt不为空 then
将bt存入队列qt中
end if
while qt不为空 do
将队头赋值给curNode
if curNode的左孩子不为空 then
将curNode的左孩子入队
end if
if curNode的右孩子不为空 then
将curNode的右孩子入队
end if
if flag的值为1 then
输出“++level:”
end if
if curNode与lastNode相等 then
将qt的队尾的值赋给lastNode
输出当前结点的值和一个逗号
将1赋给flag
else
if lastNode不等于curNode的左孩子
输出当前结点的值和一个逗号
end if
将0赋给flag
end if
将队列的队头出队
end while
2.2.2代码截图
2.2.3本题PTA提交列表说明。
Q1:提交列表显示的是不空的时候出错(有两个不空的测试点),当时测试样例能过,但是并不知道哪里有错。
A1:然后就开始自己编数据,想想各种数据的可能情况,然后就想到一个要是最后一行的叶子结点是上一行结点的左孩子,这个代码好像不能运行出来
结果,事实证明,真的不能……
Q2:然后就针对要是最后一个叶子节点是左孩子的情况进行改进。一运行,测试样例过了,一提交,又是部分正确。。。
A2:然后,疯狂编数据,发现,这么改完以后,有时候最后一个叶子结点会输出两次。
Q3:再次修改,(忘了当时怎么想的,反正一直改,一直调试)最后,我所能想到的数据都过了。开开心心的提交,部分正确。
A3:改不动了,是在是不知道该朝哪个方向进行修正,然后借鉴了同学的思路,发现只要一行到结尾的时候,将队尾的值赋给lastNode就实现了lastNode指向下一行的行末了。
2.3 修理牧场
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li 个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li 的总和。但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。请编写程序帮助农夫计算将木头锯成N块的最少花费。
2.3.1设计思路(伪代码)
//设计思路
利用有限队列的升序排列,自动将模板长度从小到大排列,每次取出两个最小值,将两个值相加,再存放到队列中,自动排序...直到队列为空。这个过程可以看作是切木板的逆过程。先找出最小的两块拼在一起,然后放回木板堆中,再找出最小的两块木板拼在一起,直至整条木板拼接完成。这样就可以实现木板割据的最小费用。
//伪代码
定义int型变量num1、num2分别用于存放队列中最小的两个数
定义int型变量add用于存放num1、num2的切割费用和,sum用于计算总薪酬,并附sum初值0
定义优先序列q,并将q自动升序排列
for i=0 to n do
输入number
将number存入队列q中
end for
while 队列q的长度大于1 do
将队头的值赋给num1
将队头出队
将此时队头的值赋给num2
将此时的队头出队
将num1与num2的和赋给add //逆过程中的最小切割费用
sum等于sum加上add的值
将add存入队列q中
end while
输出sum的值
2.3.2代码截图
ps:截图中的注释应该是升序排列,而不是降序排列
2.3.3本题PTA提交列表说明。
Q1:做这道题之前,老师有在交流群里说,这道题用哈弗曼树做的话会运行超时,可以用容器中的优先队列做。
A1:当时还不会优先队列,就想着排序的话,用数组做,再用一个sort函数就可以搞定了,每循环一次,调用一次sort函数。后来想想优先队列有一个好处,就是可以自动排序。然后就想多学一个stl容器也不错,就去找了有限队列的相关知识点。
3、阅读代码(-2--2分)
3.1 玩转二叉树
给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N(<=30),是二叉树中结点的个数。第二行给出其中序遍历序列。第三行给出其前序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树反转后的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
1 2 3 4 5 6 7
4 1 3 2 6 5 7
输出样例:
4 6 1 7 5 3 2
3.2 解题思路
这道题的解题非常的巧妙,通常人的思路可能是将正常的先序序列求出来,在将其逆序。而这个解题则是采取在层次遍历时,先将其右孩子存入数组中,再将其左孩子存入数组中的做法。
3.3 代码截图
3.4 学习体会
- 在解题时,不要固性思维,可以多想想新的解题思路。
- 可以通过学习别人的优秀代码,来扩宽自己的解题思路。有时候做题可能就会有意想不到的收获。