OO第一單元總結 表示式求導

2022-05-27 11:39:09 字數 2823 閱讀 2785

三次作業的內容均為多項式求導。第一次僅有冪函式,第二次新增了三角函式,第三次增加了巢狀因子。在格式輸入和計算過程中,前兩次都有較為固定統一的格式,而第三次由於有巢狀的遞迴表達,如果前兩次沒有專注設計(淚目)則需要尤其調整結構的問題。

整個問題可以被拆分為格式檢查求導計算輸出處理三部分。其中格式檢查和構造資料結構是比較類似的過程,但為了方便測試和除錯被我單獨分成了兩個模組(放在一起可能會節省不少工作量)。

格式檢查:拆分正規表示式

格式除了常規的匹配之外,需要注意的點有:空輸入與特殊符號指數符號絕對值表示式因子的括號等。

由於空白字元情況較一般而寫起來比較麻煩,在開始匹配之前首先排除掉空白字元的錯誤情況,然後去掉它們。特殊字元同理,先整體判一遍合法字符集。

第一次:第一次正規表示式比較簡單,但由於字串較長,大正則有爆棧風險(非捕獲組能有效降低該風險)。項的分割較為明確——運算符號,可以通過運算符號順序逐項匹配。

第二次:增加了三角和乘號。與第一次同樣的運算子分割。

第三次:採用了的方法來匹配括號,兩括號之間的字串交給第二次作業一樣的方法來處理。

求導計算

前兩次:求導都能得到固定的格式(尤其第一次),求導只需要變換類裡相應引數(但可擴充套件性基本為0),也方便優化。

第三次:通過鏈式法則構造了一顆表示式樹

類的設計

第一次:類為項,只係數和指數兩個引數;

第二次:類包含係數、三角指數和冪指數,以及求導完成後多出來的三項新的自身項(直接公式求導);

第三次:為了方便求導(懶),與表示式有關的類只有最細的因子,使用標記區分四種算符因子、四種項因子及其指數,並分別設定訪問和修改方法。

資料結構

前兩次:由於結構簡單,為了便於優化採用的一維陣列;

第三次:由於增加了巢狀而採用了表示式樹:樹的構建過程還是用棧(逆波蘭表示式),樹的分支節點為四種運算子——加減乘以及復合。其中,為了統一化,將形如 (...) 的表示式看作x與括號內表示式的復合,不需要單獨處理括號問題。樹的葉節點則為因子。第三次的二叉樹結構,把葉節點拆分到只剩最小的因子的好處是便於計算,但缺點在於樹的構成會十分不平衡,樹的層數很大。作業中由於表示式較短,樹的層數不會很深,但求導之後的層數也已經很可觀。事後我想到的優化結構的思路是使用多叉樹管理並列項。

求導過程

前兩次:公式直接求導;

第三次:通過二叉樹遞迴求導。+、-求導左右兒子;複製自身,兩個指向同一父節點(+)然後分別求導左、右兒子;復合符號根據鏈式法則在父節點複製自身後求導。

輸出優化

第一次:合併同類項,並把加號提前

第二次:合併同類項;根據 \(sin\) 降次排序後依次尋找形如 \(sin^2+cos^2=1\)的式子並化簡。

第三次:(放棄)可以考慮去掉 *1 +0之類的項,並沿著表示式樹的 * 節點丟棄含0的項,然而並沒有時間去實現。

以第三次作業為例:

類圖

部分方法複雜度

自身bug:

第一次:未處理行後空格;以及+號提前的步驟放到了求導前面,雖然功能沒錯但還是算乙個優化bug,?

第三次:錯誤地將指數上是正號判為加號。

同學bug:

​ 總的來說,bug多發區還是在wf的地方。例如非法空白字元、空格位置、空輸入輸出、棧溢位等。至於造成bug的原因,考慮不充分和測試不全面都存在。

​ 由於初次接觸oo,這幾次 面向過程 作業架構都十分凌亂,直接導致的後果就是程式可擴充套件性很差,能復用的基本只有格式判斷部分。前兩次的公式求導使得第三次**的架構必須推倒重寫。拆分項與因子的思路,在三次作業中都應該是一致的

2020北航oo第一單元(表示式求導)總結

三次作業分析 1 第一次作業 1.1 題目分析 這次作業是簡單的多項式求導。多項式由加減法連線項,項由乘法連線因子,因子為冪函式和帶符號整數。1.2 實現方案 一共建立了三個類,main類包括程式的入口,接受輸入,並將結果優化後輸出。handle類接受來自main類的表示式,並進行預處理,比如去掉空...

OO第一單元總結 多項式求導

uml類圖 oo度量 這次作業我寫了3個類,其中class struct是polynomial的內部類,這個類有2個屬性 coe index,分別代表每個項的係數和指數 polynomial類的構造方法用來判斷表示式是否合法,其他的方法用來拆分項 求導 獲取coe和index,化簡 output結果...

OO第一單元總結

由以上類圖,大體分析本次作業程式設計思路如下 2 根據資料度量分析程式結構 那麼根據以上引數含義,分析本次作業 發現,有三個方法的這三個複雜度較高,分別是ploynomial.getpoly readterm.getnum readterm.getterm 所以可以知道本次程式分別在讀入操作和獲得表...