DS博客作业05--树
1.本周学习总结
1.思维导图
2.谈谈你对树结构的认识及学习体会
学完树之后,最大的感觉就是在处理节点之间的兄弟父亲关系的时候真的挺好用的,一目了然。不过,树令人比较头疼的就是要用递归,大致能懂递归怎么用,但是自己具体写起代码来就比较懵逼,不知道把递归语句放在哪里,对递归条件判断什么的概念也比较模糊。这次的目录树大作业,我是自己独立写了一些的,但是后面发现遇到了和老师之前说的问题一样的情况,就是建立起来的树是散的,并不是一棵完整的树。在和团队讨论之后,发现需要用指针把彼此之间兄弟的关系建立起来,不过,我们队这次用的是指针,多次循环找关系,没有巧妙地运用递归,代码量就增加了不少。
这次作业,最大的收获是学会了优先队列,降序队列代码:priority_queue<int>q 升序队列代码:priority_queue<int, vector<int>, greater<int> > q。利用已有的库函数等知识点,可以大大减少编程量,这个也涉及到堆的应用,这个又和容器相关联,发现容器还真是个好东西,以后要多应用应用!
2.PTA实验作业
2.1.题目1:表达式树
输入要求:输入一行字符串
输出要求:输出结算结果,如遇到除0,提示divide 0 error!
输入样例:1+2*3
输出样例:7
2.1.1设计思路
建树初始化函数:
让叶子节点放数字,其余放运算符。初始化树的代码中定义两个栈,一个存放字符,一个存放数字,str读入的是算式
- 当str数组不为空字符的时候,进行下面循环
(1)如果str[i]是数字,就让他为叶子节点,并且进数字栈
(2)如果str[i]是字符
- 如果栈为空,则直接进栈
- 否则就和字符栈栈顶元素比较
- 如果栈顶优先级更大,则出栈两个节点存于a,b中,将两个结点以及运算符构建二叉树,将建好的树进字符栈
- 如果栈顶优先级更小,则该字符进栈
- 如果两字符优先级相等,则栈顶元素出栈
(3)
- 如果栈中和运算符不为空,则继续出栈建树,进行下面循环
出栈两个节点存于a,b中,将两个结点以及运算符构建二叉树,将建好的树进字符栈
计算结果的函数:
- 将数字字符转化为十进制数字,number1,2分别存储两叶子节点数字
- 对两叶子节点的根进行判断
- 如果是加号:result+=number1+number2
- 如果是减号:result+=number1-number2
- 如果是乘号:result+=number1*number2
- 如果是除号:
- 如果number2=0,输出提示语并且退出程序
- 如果number2!=0,result+=number1/number2
2.1.2代码截图
2.1.3本题PTA提交列表说明
- Q1:第一次出现括号错误
- A1:我以为是计算结果个函数出了问题,于是定义了一个result存放结果
- Q2:后面发现错误一样,不是这个问题
- A2:于是我向同学拿代码过来对比一下,发现在初始化树那个函数中,我并没有建立起树的关系,导致后面计算结果那个函数无法进行树无法进行遍历
2.2 题目2:输出二叉树每层结点
输入格式:输入一行字符串。空节点用#表示。
输出格式:层次遍历二叉树,按照层次输出所在层及其包含节点,节点间要求,隔开,最后一个节点尾部带,。若二叉树为空,则输出NULL
输入样例:ABD#G###CEH###F#I##
输出样例:
1:A,
2:B,C,
3:D,E,F,
4:G,H,I,
2.2.1设计思路
这题我一开始想的是按老师方法,lastNode指针是指向队列最后一个一个元素的右孩子,可是注意到他可能没有右孩子或者没有孩子的情况比较麻烦,于是就放弃这个方法。后来我发现可以用队列,想的是curNode指针一直往后找,同时他的孩子入队,找到lastNode就全部出队,那样就需要两个队列,一个放当前行数,一个放下一层元素,而且双重循环,代码阅读性不好。
后来看到同学的,可以用一个队列,curNode孩子节点依次入队,lastNode为一开始队列最后的元素,curNode为队首元素,只要两指针不相等,元素就依次出队,相等则将lastNode改为队列最后的一个元素。只要队不空,就重复前面过程。
2.2.2代码截图
2.2.3本题PTA提交列表说明
比较奇怪的是,vs上分明出现了问题,但是交上去是答案正确,这个问题目前尚未解决,解决之后博主将更新博客说明原因
2.3 题目3:修理牧场
要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。
如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。
输入格式:输入首先给出正整数N≤10000,表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。
输出格式:输出一个整数,即将木头锯成N块的最少花费。
输入样例:
8
4 5 1 2 1 3 1 1
输出样例:
49
2.3.1设计思路
这题其实就是一个哈夫曼树,要使最后的花费最小,即是要生成一棵哈夫曼树。可以利用队列,每次选取最小的两个节点合成一棵树,由于这样要排序与合并,用数组就会比较麻烦。老师提示说可以用优先队列,其实就是一个堆的问题,放进一些无序的数进去,会自动排好序。
降序队列代码:priority_queue<int>q 升序队列代码:priority_queue<int, vector<int>, greater<int> > q
- 先让全部元素入队,优先队列会自动排好序
(1)队大小不为1的情况前两个元素出队,相加和存于cost中
(2)将cost放入队列中
(3)定义一个total记录最后总的费用,total每次自增cost
(4)队列大小不为1的情况下,cost重新置为1,再重复步骤(1)
(5)最后输出的total即所求的最小花费
2.3.2代码截图
2.3.3本题PTA提交列表说明
这题还比较顺利,由于老师有说过思路,就未犯什么错误
3、阅读代码
3.1 题目
本题为天梯赛试题,给定一个庞大家族的家谱,要请你给出最小一辈的名单。
输入格式:
输入在第一行给出家族人口总数 N(不超过 100 000 的正整数) —— 简单起见,我们把家族成员从 1 到 N 编号。随后第二行给出 N 个编号,其中第 i 个编号对应第 i 位成员的父/母。家谱中辈分最高的老祖宗对应的父/母编号为 -1。一行中的数字间以空格分隔。
输出格式:
首先输出最小的辈分(老祖宗的辈分为 1,以下逐级递增)。然后在第二行按递增顺序输出辈分最小的成员的编号。编号间以一个空格分隔,行首尾不得有多余空格。
输入样例:
9
2 6 5 5 -1 5 6 4 7
输出样例:
4
1 9
3.2 解题思路
家族人数其实就是一棵树对应的层层父亲兄弟孩子之间的关系,输入的N个节点对应的编号是其父母,由此可建成一棵树。而题目需要输出最小辈分即是层次遍历树,输出最后一层节点,也就需要用队列进行广度搜索。
3.3 代码截图
3.4 学习体会
- 看完这个代码发现根据父亲结点来建树会比给出先序序列那些逻辑性更强一些,这就需要建树的时候控制好他们之间的关系
- 利用广度遍历找到最小字辈,用到了vector,可很方便实现排序等功能