OO第一單元總結(jié)(表達(dá)式求導(dǎo))
前言
OO第一單元一共有三次代碼設(shè)計(jì)作業(yè),主題是表達(dá)式求導(dǎo),從最初的簡單多項(xiàng)式求導(dǎo),到之后的三角函數(shù)求導(dǎo),再到嵌套因子的求導(dǎo),可謂是逐層遞進(jìn),引人入勝。其中也給我留下了許多值得珍惜的回憶,在此,我將用博客的形式將其總結(jié)一下,來為第一單元畫上一個(gè)完美的句號(hào)。
第一次作業(yè)
作業(yè)內(nèi)容
第一次作業(yè)需要完成的任務(wù)為簡單多項(xiàng)式導(dǎo)函數(shù)的求解,由于求導(dǎo)模式較為簡單,并且保證了輸入表達(dá)式的合法性,因此總體難度一般。

思路分析
通過閱讀作業(yè)內(nèi)容,我們可以知道,輸入字符串為表達(dá)式的形式,而表達(dá)式又由項(xiàng)組成,因此我們自然而然的想到了將表達(dá)式拆分成很多個(gè)項(xiàng),然后對(duì)每個(gè)項(xiàng)進(jìn)行求導(dǎo),最后再連接起來輸出。考慮到本次作業(yè)的項(xiàng)僅僅是ax^b的形式,因此我沒有將項(xiàng)進(jìn)一步細(xì)分為因子然后再求導(dǎo),而是利用求導(dǎo)公式直接對(duì)項(xiàng)進(jìn)行處理,因此缺乏一定的可擴(kuò)展性,不過解決這個(gè)問題已經(jīng)是綽綽有余了。最后再將相同指數(shù)的項(xiàng)進(jìn)行合并,優(yōu)化輸出效果。
基于度量的程序結(jié)構(gòu)分析
方法度量

本設(shè)計(jì)使用的方法數(shù)不算太多,有很大一部分是Term類中的get和set方法,而main中主要承擔(dān)了字符串的處理以及輸出等工作。
類度量

這次作業(yè)僅僅使用了兩個(gè)類,分別是主類和項(xiàng)類,因此還有很大一部分的面向過程的影子,并且主體集中在主類中。給我的感受是處理起來還比較方便,但是如果要在此基礎(chǔ)上添加新的功能,可能就不再適用了,因此我在之后的作業(yè)中開始考慮起了面向?qū)ο蟮乃枷耄渤晒Φ膶?shí)現(xiàn)了多種形式求導(dǎo)的功能。
類圖分析

此類圖闡明了兩個(gè)類的相互關(guān)系,即主類中create了Term類。
Bug分析
自身bug
可能是由于功能較為簡單的原因,第一次作業(yè)在強(qiáng)測(cè)和互測(cè)中均未發(fā)現(xiàn)bug。
他人bug
第一次作業(yè)沒有搭建評(píng)測(cè)機(jī),而是直接手動(dòng)設(shè)計(jì)了一些測(cè)試數(shù)據(jù),再加上作業(yè)功能要求單一,不容易出現(xiàn)錯(cuò)誤,因此沒能捕獲到他人的bug。
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn)
這次作業(yè)設(shè)計(jì)的亮點(diǎn)在于對(duì)字符串的處理以及合并同類項(xiàng)。在處理字符串時(shí),我采用了整體設(shè)計(jì),即將整個(gè)字符串一次性讀入,然后再進(jìn)行拆分處理,而不是一個(gè)一個(gè)字符的讀入,這樣做的好處在于簡單并且淺顯易懂,大致設(shè)計(jì)如下:


另外在處理項(xiàng)合并時(shí),可以通過使用ArrayList,來調(diào)用每個(gè)項(xiàng)的指數(shù)、系數(shù),然后進(jìn)行判斷與合并,這其中我用到了coeff和index及其各自的get、set方法。
缺點(diǎn)
劃分還不夠細(xì)致,最終只停留在處理項(xiàng)上,而沒有進(jìn)一步細(xì)分為因子之間的運(yùn)算,需要進(jìn)一步改進(jìn)或者重構(gòu)。
第二次作業(yè)
作業(yè)內(nèi)容
本次作業(yè),需要完成的任務(wù)為包含簡單冪函數(shù)和簡單正余弦函數(shù)的導(dǎo)函數(shù)的求解。備注:包含嵌套括號(hào)!!!難度瞬間提起來了。

思路分析
花了long time看完題目之后,我受到了降維打擊。苦苦思考了幾天,最初打算在第一次作業(yè)基礎(chǔ)上進(jìn)行改進(jìn),后來發(fā)現(xiàn)無論如何也解決不了括號(hào)嵌套的問題,因此不得不放棄這個(gè)思路。然后我想到,要不先嘗試把括號(hào)全部展開,讓每一項(xiàng)都變成ax^bsin(x)^mcos^n的形式,然后再對(duì)每一項(xiàng)進(jìn)行求導(dǎo),最后合并輸出。事實(shí)上,理想是美好的,并且后面的步驟也并不算難,而真正的難點(diǎn)就是前面的括號(hào)展開功能,這個(gè)功能我始終實(shí)現(xiàn)不了,無奈之下也不得不放棄。最后我選擇了重構(gòu),這來自于表達(dá)式樹給我的啟發(fā),因?yàn)楸磉_(dá)式樹的葉子節(jié)點(diǎn)剛好可以存放因子,而根節(jié)點(diǎn)可以存放符號(hào),因此到時(shí)候只需要一次遍歷,就能夠訪問整個(gè)表達(dá)式。關(guān)于求導(dǎo),在遍歷過程中,會(huì)對(duì)每一個(gè)節(jié)點(diǎn)的內(nèi)容進(jìn)行判斷,如果是符號(hào),則按照符號(hào)規(guī)則計(jì)算其導(dǎo)數(shù)。當(dāng)然,其中會(huì)使用到孩子節(jié)點(diǎn)的導(dǎo)數(shù)和子樹的內(nèi)容,構(gòu)成一種遞歸的模型。對(duì)于表達(dá)式樹的建立,我將它的過程分為了兩步,首先將輸入的表達(dá)式由中綴轉(zhuǎn)換成后綴表達(dá)式,然后再利用后綴表達(dá)式建立二叉樹。總體而言,第二次作業(yè)要用到很多數(shù)據(jù)結(jié)構(gòu)的知識(shí),包括容器、棧、二叉樹等,但是理解起來并不難,只要合理使用、互相配合即可。
基于度量的程序結(jié)構(gòu)分析
方法度量

本次作業(yè)的方法數(shù)相對(duì)較多,畢竟要實(shí)現(xiàn)較為復(fù)雜的功能,由于是重構(gòu)過的設(shè)計(jì),因此與第一次作業(yè)的方法已經(jīng)大體不一樣了,但是也還是能夠看到第一次作業(yè)的影子,比如對(duì)字符串整體的處理,讓它變化成我們想要的樣子。
類度量

本次設(shè)計(jì)包含四個(gè)類,主體是主類和樹類,已初步具有面向?qū)ο蟮乃枷耄孕枰M(jìn)一步細(xì)化。
類圖分析

此類圖包含了四個(gè)類的相互關(guān)系,主類僅與Tree類相聯(lián)系,而Tree類中使用到了Node類和Str類,他們之間存在著交互。
Bug分析
自身bug
本次作業(yè)在互測(cè)和強(qiáng)測(cè)中都出現(xiàn)了錯(cuò)誤,導(dǎo)致扣分較多,一方面的原因是提交之前沒有進(jìn)行充分的測(cè)試,使得一些隱藏的錯(cuò)誤沒有被發(fā)現(xiàn)出來,另一方面是本次作業(yè)進(jìn)行了重構(gòu),較為復(fù)雜,因此產(chǎn)生了許多新類型的錯(cuò)誤。經(jīng)過對(duì)測(cè)試數(shù)據(jù)的觀察與反思,我發(fā)現(xiàn)問題主要出在一個(gè)不起眼的地方,就是在處理“-(”的時(shí)候,我的架構(gòu)缺少了這一情況,但是如果將“-(”換成“-1*(”就可以了,所以相當(dāng)于最終就只有一個(gè)bug,啦!
他人bug
本次互測(cè)我采用了評(píng)測(cè)機(jī),成功的hack到了三個(gè)人,其中有一個(gè)是在處理sin(x)^3*cos(x)^5的時(shí)候出現(xiàn)了問題,不知道為什么求導(dǎo)的結(jié)果只有一項(xiàng)了,正常應(yīng)當(dāng)是兩項(xiàng),這讓我印象比較深刻。當(dāng)然了,不同的人所產(chǎn)生的bug也不盡相同,主要還是要綜合考慮清楚所有的情況,不能因?yàn)橥祽卸笠馐韬觥?/p>
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn)
本次作業(yè)我采用了表達(dá)式樹的方法,成功的解決了字符串求導(dǎo)問題,并且具有較好的可擴(kuò)展性,這一點(diǎn)在第三次作業(yè)中可以體現(xiàn)出來。
缺點(diǎn)
由于進(jìn)行了重構(gòu),導(dǎo)致時(shí)間緊張,來不及處理優(yōu)化問題,因此性能分不高。
第三次作業(yè)
作業(yè)內(nèi)容
本次作業(yè),需要完成的任務(wù)為包含簡單冪函數(shù)和簡單正余弦函數(shù)及其嵌套組合函數(shù)的導(dǎo)函數(shù)的求解,此外,還要判斷輸入表達(dá)式的合法性。

思路分析
本次作業(yè)看似很復(fù)雜,但事實(shí)上,在第二次作業(yè)的基礎(chǔ)上,本次作業(yè)需要修改的地方并不是很多。關(guān)于求導(dǎo),本次作業(yè)的要求僅僅是多了一個(gè)sin和cos中包含表達(dá)式因子的情況,這個(gè)用我搭建的表達(dá)式樹可以輕松解決,方法是將sin和cos看成是一個(gè)分支結(jié)點(diǎn),然后其內(nèi)部表達(dá)式因子作為其左孩子結(jié)點(diǎn),其右孩子結(jié)點(diǎn)為空,在求導(dǎo)時(shí)僅調(diào)用左孩子結(jié)點(diǎn)內(nèi)容即可。然后對(duì)于Wrong Format的判斷,我采用的是列舉所有可能出現(xiàn)的錯(cuò)誤情況,對(duì)癥下藥,依次進(jìn)行判斷和解決,這個(gè)方法比較麻煩,但是思考起來并不復(fù)雜。
基于度量的程序結(jié)構(gòu)分析
方法度量

類度量

由于在第二次作業(yè)的基礎(chǔ)上,本次作業(yè)無需改變太多,因此依然只使用了四個(gè)類,大部分修改也僅僅是在MainClass和Tree類中,較為方便。
類圖分析

此類圖與第二次作業(yè)中的類圖大體一致,僅僅是有些類中的方法發(fā)生了一定的變化,主要體現(xiàn)在MainClass中。
Bug分析
自身bug
本次作業(yè)在互測(cè)中沒有發(fā)現(xiàn)bug,可能是因?yàn)榛y(cè)輸入的數(shù)據(jù)都是合法的,然而在強(qiáng)測(cè)中我出現(xiàn)了一個(gè)問題,就是在包含sin(+ 1)的時(shí)候,由于帶符號(hào)整數(shù)的符號(hào)與數(shù)字之間不能有空白字符,而此式我沒能判斷出來是Wrong Format,所以錯(cuò)了,這也是考慮不周的效果。
他人bug
我使用cos(0)**2*x一次性hack到了兩個(gè)人,他們其中一個(gè)是在運(yùn)行時(shí)會(huì)報(bào)錯(cuò),另一個(gè)輸出了類似于cos()的東西,也是很奇怪。總而言之,bug都是千奇百怪的,不同的人會(huì)犯不同的bug,及時(shí)發(fā)現(xiàn)并修改就好了。
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn)
在第二次作業(yè)重構(gòu)之后,本次作業(yè)需要添加的東西不多,這也體現(xiàn)了面向?qū)ο蟮乃枷耄岣吡丝蓴U(kuò)展性,讓我感到很欣慰。
缺點(diǎn)
對(duì)Wrong Format的判斷還有待改進(jìn),對(duì)性能的優(yōu)化也需要尋找新的方法,應(yīng)當(dāng)多多學(xué)習(xí)討論區(qū)里的內(nèi)容。
重構(gòu)經(jīng)歷總結(jié)
隨著題目難度的增加,題目要求的變化,我們之前的設(shè)計(jì)可能已經(jīng)適應(yīng)不了新的需求,因此往往需要重構(gòu)。這次作業(yè)我包含兩個(gè)設(shè)計(jì),一共重構(gòu)了一次,說實(shí)話,重構(gòu)其實(shí)還是充滿許多挑戰(zhàn)的,因?yàn)橐獜闹暗乃季S習(xí)慣跳轉(zhuǎn)到另一個(gè)全新的設(shè)計(jì)中,所有還要考慮許多方面的內(nèi)容。為了解決表達(dá)式樹的問題,我還特意翻了翻大一下學(xué)期學(xué)的數(shù)據(jù)結(jié)構(gòu)有關(guān)棧的知識(shí),因?yàn)槟莻€(gè)時(shí)候做過類似的題目,只是不包含求導(dǎo)而已。在我看來,重構(gòu)是很有必要性的,我們?cè)诮鉀Q某個(gè)問題時(shí),就應(yīng)當(dāng)去思考未來可能需要增加的需求,思考我們?cè)撊绾翁砑游覀兛赡苄枰砑拥膬?nèi)容,這一方面可以減少重構(gòu)的次數(shù),另一方面也加強(qiáng)了我們對(duì)于這個(gè)的問題的思考深度。
心得體會(huì)
第一單元的作業(yè)讓我感受到了面向?qū)ο蠹夹g(shù)的優(yōu)越性,它在解決問題時(shí)具有良好的可擴(kuò)展性,這在一些企業(yè)里面是十分重視的一點(diǎn)。表達(dá)式求導(dǎo)問題還可以包含許多其他的功能,比如對(duì)數(shù)函數(shù)求導(dǎo)、tan求導(dǎo)、偏導(dǎo)數(shù)、多次求導(dǎo)等,我們?cè)谡n余時(shí)間也可以去多想想,提高自我的全局掌控能力,以適應(yīng)將來的發(fā)展。這段時(shí)間的編程一方面提高了我的java水平,另一方面也改變了我的編程思想,開始有了變化,變得更加深刻了,而不是停留于淺顯的層次。總而言之,完成第一單元后,我既充滿喜悅,也充滿對(duì)未來幾單元的期待,希望能夠順利通過,加油吧!
浙公網(wǎng)安備 33010602011771號(hào)