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

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

1、第1、第二次做業總結

  由於前兩次做業設計複雜度差異不大,於是放在這裏統一總結。正則表達式

基於度量分析程序結構:

前兩次做業確實存在缺少可拓展設計的構想,基本仍是面向過程的思惟方式。「一類到底,一main到底」,由於有代碼風格的要求被迫將代碼模塊化(捂臉)。算法

初次接觸正則表達式,第一次設計正則表達式的時候並不知道正則的內部實現,出現了「一個大正則」,後來瞭解到許多正則匹配模式(貪婪,懶惰,獨佔)。兩次做業都改爲了小正則匹配同時捕獲,這樣能夠有效避免正則爆棧的問題。shell

String expon = "[\\t ]*(\\^[\\t ]*[+-]{0,1}\\d{1,}){0,1}[\\t ]*";//指數
String subterm = "([\\t ]*(\\*[\\t ]*" +        //後續表達式
        "(((cos[\\t ]*\\([\\t ]*x[\\t ]*\\)[\\t ]*)|" +
        "(sin[\\t ]*\\([\\t ]*x[\\t ]*\\)[\\t ]*)|x)" +
        expon + "|([+-]{0,1}\\d{1,}[\\t ]*))))*";
String regax1 = "([\\t ]*\\d{1,}[\\t ]*" + subterm +    
        "|([\\t ]*((cos[\\t ]*\\([\\t ]*x[\\t ]*\\)[\\t ]*)|" +
        "(sin[\\t ]*\\([\\t ]*x[\\t ]*\\)[\\t ]*)|x)" +
        "(" + expon  + subterm  + "|" + subterm + ")" + ")" +
        "|([\\t ]*[+-]\\d{1,}"  + subterm + ")" +
        ")";
String regex = "([\\t ]*[+-][\\t ]*" +      //表達式開頭
                "((((cos[\\t ]*\\([\\t ]*x[\\t ]*\\)[\\t ]*)|(sin[\\t ]*\\([\\t ]*x[\\t ]*\\)[\\t ]*)|x)" + expon + subterm + ")" +
                "|([+-]" + regax1 + ")" +
                "|(\\d{1,}[\\t ]*"  + subterm + ")" +
                ")[\\t ]*)";

 

  設計正則表達式時,我運用了簡單的樹結構,由於每一個項的第一個因子較爲特殊,因此單獨設計,每一個項的後續因子具備重複性,因此統一設計。(其實就是暴力列舉全部狀況)模塊化

  求導處理方面,由於沒有很好考慮到可拓展性,簡單的暴力求導,公式以下:優化

     $(ax^bsin(x)^ccos(x)^d)′=abx^{b-1}cos(x)^dsin(x)^c+acx^bcos(x)^{d+1}sin(x)^{c−1}−adx^bcos(x)^{d−1}sin(x)^{c+1}$

  存儲方面,利用Arraylist存儲每個項,每一個項內存儲各個因子的指數。由於後來才解了Hashmap,發現對於前兩次做業,Hashmap比ArrayList合併時有更大優點。spa

程序bug分析

  bug主要存在於輸出方面的,由於優化時想去除常數因子爲0的項,由於考慮不周,因此出現+0無輸出的bug。操作系統

發現別人bug的策略

  一、聚焦於WF檢測,根據本身設計的正則反向構造許多反例,可是發現你們WF寫的都很好,確實難頂。設計

  二、設計一些邊緣數據,好比0*sin(x)^0。(在我那個組基本沒用,你們都統一設計,未發現刁鑽數據一刀hack1人以上)code

  三、借別人的數據來測·····難頂對象

  四、寫了個shell腳本,能用操做系統的知識解決一次測一組人的實際需求(太頂了)

2、第三次做業總結

  此次做業簡直就是地獄,週五髮指導書,原本還想沿用前兩次的正則構造思想,大量查閱資料,發現要遞歸定義正則(本身定義本身),實在是寫不出來,放棄了這個選擇。週六周天毫無頭緒,週一瞭解到了一個遞歸降低的算法,看懂代碼以後原本想拿來主義變成本身的,可是無奈本身沒法復現如此精妙的遞歸降低,週二凌晨3點重構,從頭開始。

本次做業主要分紅兩個工做:

  一、WF判斷,這一部分我並不想前兩次,在處理以前就判斷,而是考慮到括號的遞歸存在,因此在處理時若是不符合簡單小正則規範,則輸出WF(在這以前有「錯誤符號檢測」「空格及製表符模式檢測」「+-符號個數檢測」)。

  二、求導,針對此次做業十分複雜的特性,使用遞歸求導:

    1)、Poly求導結果爲Poly中的Term求導相加

    2)、Term求導爲Term中每一個Factor求導後與剩餘全部Factor相乘;

    3)、Factor求導分爲5大類:x、sin(x)、cos(x)、constant、Polyfactor,其中Polyfactor求導遵循1)規則

  表達式處理是我認爲本次做業最難的部分,我採用的(借鑑的)辦法是,用+將Poly分紅Term(在這以前用棧的方式,標記處於每一個Term外的+,將Term內的+換成別的符號),而後用*將Term分紅Factor(分紅Factor過程分爲5類,同時進行簡單小正則WF判斷),進而求導。(這裏注意,在求導前,全部構造已經完成,即已經將全部表達式因子(Polyfactor)拆分紅新的Term)

  (Poly和Term之間不存在繼承關係,Factor與其餘5個因子均爲繼承關係)

3、說說本身的理解

  以上即爲個人方法(借鑑吸取別人的方法),下面我想重點介紹我理解的(僅僅我的理解,歡迎大牛指導批評),僅針對本題的遞歸降低算法:

  遞歸降低算法在本題主要針對於表達式處理,由於代碼版權屬於別人(我真菜),就不貼代碼了,簡單介紹一下:

    1)、各個類的構造辦法比較平凡,和個人辦法中類的構造大同小異。

    2)、在斷定表達式WF中(前提是已經進行了「無效字符檢查」「空格格式檢查」),採用的方式是將問題下放,在最終的各個因子中進行「小正則」的簡單檢查。

      eg:sin((x)

      總體方法:調用toPoly()方法,toPoly()方法中調用toTerm()方法,toTerm()方法中調用toFactor()方法,toFactor()方法先檢測到這屬於sin類,判斷「sin(」 是否存在且合法,而後跳過,接着對於中間的部分進行toFactor()方法繼續構造(根據定義,sin括號內必須爲一個5種因子(constant,sin,cos,x,Polyfactor)中的一種),接着回到toFactor()方法,檢測後面的「)」,即完成了Sin(Factor)檢查,(至於Factor是否合法,那是Factor的事)。

      追蹤本eg:toFactor()方法,判斷「sin(」 存在且合法後,跳過「sin(」,接着對於中間的部分使用toFactor()方法繼續構造,在toFactor中發現了一個‘(’,所以判斷它爲一個Polyfactor類型的Factor,繼續調用toPolyFactor()方法,toPolyFactor()方法構造完畢(結果爲取出了「(x)」)後返回至最初的toFactor()方法檢查最後的「)」,發現沒有這個「)」,由於已經將「)」匹配給了裏面的「(x)」,進而拋出異常,輸出WF。

    3)、這種方法我讀懂以後讓我驚歎大天然的鬼斧神工(還有本身真菜)。我的認爲它的精妙之處在於,他不關注頂層Poly如何構造,只須要知道Poly是一個一個Term構成的;同時也不須要知道Term怎麼構造,由於它是一個一個Factor構成的。全部全部的問題只存在於,如何寫出正確的Factor構造(這相對簡單不少啊)。全部表達式提取問題迎刃而解。

    看完這份代碼,我感受到本身的眇小與可憐兮兮。僅僅針對本題,我認爲這個遞歸降低的思想也許蘊含了面向對象的不少道理,不關心大問題的具體實現,只關心大問題能夠由解決哪些小問題來解決,而後利用對象或方法來解決小問題,在這點上,差很少是我第三次做業的最大收穫了。

(默默感謝對我提供幫助的大牛們)

相關文章
相關標籤/搜索