- 表达式中仅含有\(x,y,z\)三种未知数
- 表达式仅含有\(+,-,*,**,\sin,\cos,dx,dy,dx\)几种运算
- \(dx,dy,dz\)分别表示对\(x\)求导,对\(y\)求导,对\(z\)求导。
- **表示乘方,例如\(2**3=2^3=8\)- 包含若干自定义函数。
- 化简后的结果除必要括号(三角函数运算符号带的必要括号)外不含其他括号。
对于表达式的问题很自然就会想到用栈去处理。
定义运算符的优先级。
| 运算符 | 优先级 |
|---|---|
| ) | 0 |
| +、- | 1 |
| * | 2 |
| ** | 3 |
| ( | 4 |
首先考虑如果表达式中不含字母只含数字应该如何计算。考虑双栈结构按照如下流程处理
(这里仅讨论主体架构,关于细节方面就不再赘述)。
对于求导运算与三角函数运算,他们都是单元运算,并且运算作用范围必有一对(),
因此当符号栈顶为求导运算和三角函数时直接取出计算即可。
PS:有关自定义函数的处理,我采用了一种比较简单直接的办法——字符串替换。即把实参截取出来将函数表达式中的形参替换掉。
我们仔细思考用栈计算表达式的流程,容易发现其只关心表达式的运算结果而并不关心表达式的层次结构。
所以后续的作业关键点就转换成了如何用合理的数据结构表示运算结果。
第一次作业当中不含三角函数、自定义函数以及求导,因此输出结果仅表现为若干单项式的和。
于是用单项式组合成多项式的结构并定义单项式类及多项式类的加法乘法就能很轻松的解决。
第二、三次作业引入了三角函数,上述结构便不再适用了。
引入三角函数之后的难点在于三角函数之间的相互嵌套。这种互相嵌套的结构类似于树结构,于是我们考虑用类似表达式树的结构表示运算结果。
每个树结点记录两个信息:
对于叶子结点只需记录此结点对应的多项式(即将第一次作业的设计封装进去)
例如树
即表示表达式\(\sin(x^2*y+z)+\cos(x^4*x*z*y)\)
接下来只需要定义两棵树之间的加法和乘法。
两棵树的加法:
两棵树a,b的乘法:
当然仅仅只做好树的乘法和加法是不够的,因为这还无法实现化简的目的。为此,我们还需要做以下约定:
加入求导因子后,只需按照求导法则为树建立求导方法即可。
为了简单起见,下面以一棵普通的无根树为例
从叶子结点开始,我们给每个特定的结构一个唯一的编号。
往上一层出现了两种新的结构,
我们给他们标号为2,3
又出现了新的结构
编号为4
最后给结构
编号为5
至此,所有不同的树结构都有了一个独一无二的编号,我们就可以很方便的依据这个编号合并同类项了。
但是本人并没有在作业中实践这个树哈希,只是口胡了一下,感觉为了这点性能分不是很有必要,也没有什么意思,遂润去cf、atc玩耍。
PS:此方法也可以用来判定两棵无根树同构,方法是找到两棵树的重心并以重心为根进行树哈希(由于树可能有两个重心,所以最坏情况下要做四次。)
作为没有选先导课,寒假又完全没有预习的人(其实寒假买了大黑书的,但直到开学它都还是崭新的bushi)刚开始对于不会java还是有点慌的,但是好在编程语言之间的本质都是相通的,我对C/C++也比较熟悉,于是看了1个多小时java语法遂上手开始写代码。
于是就出现了辛辛苦苦写完了一个方法,却被告知是java库里自带的。。。(卒)
很奇怪的一点,作业开始之前所有人都告诉我不要用栈去写,根本写不出来。但是实际上我写下来并没有感觉到什么阻力,而且用栈写考虑的重点就只有多项式的乘法加法,第二次作业就变成树的乘法加法,第三次作业就加个树的求导。这样的思路不是应该比什么递归下降又是term又是factor又是expr的设计更自然更简单嘛。
还有一种说法是栈并不能体现表达式的层次结构,我觉得也不尽然,栈并非不体现层次结构,而是把层次结构表现在计算结果中了。
因此,我并不觉得表达式求值适合作为面向对象的作业,我觉得一切架构的设计都是为了让问题变得简单,使问的本质更加清晰。
而表达式求值的本质已经足够简单清晰了,再去拼命想所谓精妙架构反而会使问题复杂化。建万丈高楼需要稳固的脚手架,但是搭玩具积木再这么做就完全没有必要。
不管是面向过程、面向对象还是面向函数,任何编程模式的设定都是为了简化问题,解决问题就是要回归到问题本身具体问题具体分析,把表达式作为课程的作业就有为了面向对象而面向对象之嫌。
华罗庚说过数学就是要足够的退退到原始而又不失本质的地方,我觉得程序设计也是如此,既然栈--树的设计已经触及到了问题的本质,那就不必反其道而行之。
说实话,对于本人来说,这次作业写下来着实有些无聊,题目也显得过于稀松平常,略有挑战的地方在于代码规模,以前写过最长的代码就是200行左右的Link-cut-tree、动态DP、树套树之类的玩意。这次作业总代码量已经有800+行,但写完之后完全没有写出上述算法之后的喜悦感和成就感,感觉只是完成了课程的一个任务罢了。
另外,年年表达式、年年电梯,难道不腻吗,是不是该换换题了呢?
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir
假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。
根据ActiveRecord::Base的文档:==(comparison_object)Returnstrueifcomparison_objectisthesameexactobject,orcomparison_objectisofthesametypeandselfhasanIDanditisequaltocomparison_object.id.Notethatnewrecordsaredifferentfromanyotherrecordbydefinition,unlesstheotherrecordisthereceiveritself.Besides,ifyoufet