1. 程式人生 > 其它 >BUAA_OO_第一單元總結與反思

BUAA_OO_第一單元總結與反思

BUAA_OO_第一單元總結與反思

目錄

摘要

本單元有三次作業,作業題目就是,輸入一個表示式字串,對這個字串進行處理,要求輸出被去掉括號的表示式字串。下面說明各次作業的因子型別。

  • Homework1:
    • 變數因子
      • 冪函式
        • 一般形式
          由自變數 x,指數符號 ** 和指陣列成,指數為一個非負帶符號整數,如:x ** +2
        • 省略形式 當指數為 1 的時候,可以省略指數符號 ** 和指數,如:x
    • 常數因子 包含一個帶符號整數,如:233
    • 表示式因子 用一對小括號包裹起來的表示式,可以帶指數,且指數為一個非負帶符號整數,例如 (x**2 + 2*x)**2 。表示式的定義將在表示式的相關設定中進行詳細介紹。
  • Homework2:下面只列出第二次作業相對於第一次作業增加的因子
    • 三角函式
    • 自定義函式
    • 求和函式
  • Homework3:下面直解釋第三次作業相對於第二次作業對於因子的改動
    • 允許巢狀因子的三角函式

第一次作業

架構分析

第一次作業接觸到層次化遞降的架構,基本思路就是把把表示式裡的項提取出來,把化簡表示式的問題降到化簡項,再把項裡面的因子提取出來,把化簡項的問題降到化簡因子。這是遞降,把任務這一層的任務推給下一層,然後用下一層的結果來得出本層的結果。

效能分策略

只要將表示式的括號展開去掉以後正確性就達到了,效能分要靠縮短化簡的表示式來得到。基本就是合併一下同類項,因為輸入資料有冪次限制,採用的陣列的方法,acc[0]就記錄0次冪的項的係數之和,acc[1]記錄一次冪的項的係數之和,....最終輸出的時候,再讓0次冪的項輸出為常數,x**1輸出為x,x**2輸出x*x。

本次作業UML圖

  • Expr類

    • toterm方法返回一個Arraylist,裡面存放從表示式中提取出來的項
    • mergexpr是再展開的基礎上返回一個合併同類項的表示式
  • Term類

    • mul方法對兩個被化簡的因子做乘法,返回得到的字串
  • Factor類

    • xiaohao方法就是把因子前面的若干個正負號消成一個正負號

​ 這三個類的toString方法都是返回一個字串,這個字串是本層次化簡得到的字串。

缺點:採用陣列的方式進行合併同類想,不利於後續的迭代

優點:基本建成了遞降的結構

效能分策略

只要將表示式的括號展開去掉以後正確性就達到了,效能分要靠縮短化簡的表示式來得到。基本就是合併一下同類項,因為輸入資料有冪次限制,採用的陣列的方法,acc[0]就記錄0次冪的項的係數之和,acc[1]記錄一次冪的項的係數之和,....最終輸出的時候,再讓0次冪的項輸出為常數,x**1輸出為x,x**2輸出x*x。

bug解析

這次作業出現兩個bug

  1. 第一個bug

    • 我想的是:0+x輸出為x,0+3*x輸出為3*x,目的就是去掉行首的0+

    • bug出現:-20+x輸出為-2x,-50+x輸出為-5x,使用replace方法的時候暴力去掉0+

      修復bug:再把replace的reg由“0[+]”改為“^0[+]”

  2. 第二個bug

    • 例子:-(x)**0輸出1,-(x+x)**0輸出1

      就是說對於0次冪的表示式因子沒有忽略了它的符號(我把因子前面的符號也看成因子的一部分)

度量分析


Hack策略

用java寫了一個生成測試樣例的程式,然後用大量的樣例去盲測比對同房間的同學的輸出。最終只hack出兩個bug。

第二次作業

架構分析

遞降關係大體上還是與第一次作業相同,不同的在於第二次因子結構更加複雜,我第一次作業使用正則表示式的方法,為每一個因子寫一個Pattern,來提出項和因子,達到遞降的目的。但是這一次因子的Pattern不好寫,於是我還是新建一個類來專門去識別因子。

本次作業UML圖

  • 先對Expr,Term以及六種因子中都有出現的gethash方法進行解釋,這個方法是返回一個 HashMap<HashMap<String,BigInteger>,BigInteger>,裡面儲存了化簡得到的表示式。這個HashMap的每一項,也就是說每一對Key和Value的意義記錄被化簡的表示式的一個項的資訊,Value也就是外層的BigInteger記錄的是這個項的係數,Key也就是內層的HashMap的每一項記錄的是項內一個因子的資訊,String記錄的是因子的底數,BigInteger記錄的是因子的冪次。
    舉例說明就是2*x**2*sin(x)**3+1*x,那麼這個表示式的第一項存到我的HashMap中就是,第一項的外層BigInteger為2,內層HashMap存了兩個因子,<"x",2>和<"sin(x)",3>。

  • Skip類說明,這個類是專門建立用來識別因子和提出因子的。

    舉例來說:-(x+sin(x))**2+x**3+1,這是一個表示式字串,我一個一個字元去遍歷這個字串,int i = 0,i現在指向第一個字元,一個負號,然後i++,一個括號,這個時候我就確定這是一個表示式因子,我呼叫針對表示式因子的方法,來獲取這個因子的最後一個字元的位置,在這個表示式中為2,呼叫substring方法提取出這個因子-(x+sin(x))**2(我把負號也看成這個因子的一部分),然後把對i賦值讓它指向下一個因子的開始,也就是2後面的加號,然後繼續遍歷,讀到x的時候,我知道這是一個冪函式因子,我呼叫針對冪函式因子的方法去得到這個因子的最後一個字元的位置,然後substring連帶正好提取出這個因子+x**3,然後讓i指向這個因子之後第一個字元,也就是3後面的那個加號...

    可以利用這個類去提取項。

  • Operate類中兩個方法add()用來將化簡項得到的HashMap合併成表示式的HashMap,mul()用來將化簡因子得到的HashMap合併成項的HashMap。

  • Functionlib的作用在於它的屬性static HashMap<String,String>,作用是儲存輸入的自定義函式的資訊,key為函式名,value是函式的表示式。提供一個全域性變數的作用。使得Functionf(用於化簡自定義函式的類)中的方法可以訪問到自定義函式的資訊。

缺點:有重複造輪子,有些類裡面有一些十分相似的方法,也許可以建立一些繼承關係。

優點:使用了巢狀的HashMap儲存化簡的表示式資訊,比較容易進行乘法加法。

效能分策略

大體和第一次作業相似,就是合併了一下同類項,但是這一次我採用HashMap<HashMap<String,BigInteger>,BigInteger>

來儲存每一個層次化簡得到的表示式。所以合併同類項的方法就是寫好HashMap的合併方法。

主要在兩個方面,

  • 一個是要用因子的HashMap來得出項的HashMap,也就是要得到因子做乘法得到結果對應的HashMap
  • 一個是要用項的HashMap來得出表示式的HashMap,也就是要得到項做加法得到結果對應的HashMap

bug解析

強測出了一個bug

舉例說明:sin(x**2)輸出sin(x^2),sin(x**3)輸出sin(x^3),

原因很明顯,對輸入的字串進行預處理的時候,把**替換成,最後輸出的時候忘了把三角函式括號裡面的換回來,很容易修復。

度量分析

Hack策略

這次沒用大量的資料樣例轟炸,因為沒有寫生成資料的程式,所以就是隨手自己測一測一些邊界資料,例如0次方,sin(0),cos(0)。

第三次作業

架構分析

這一次作業工作量較少,就是在第二次的基礎上改進了三角函式因子的化簡,第二次作業遞降到三角函式因子就到最底層了,這一次三角函式裡面允許巢狀因子,也就是三角函式因子可能再遞降到表示式的層次。就對三角函式因子括號內的內容分情況進行了處理。

本次作業UML圖

這一次作業相對於第二次作業改動很少,就是改動了Trigf的getkuohaoli方法,讓它呼叫Expr類來對三角函式括號裡的字串來進行化簡。

效能分策略

相對於第二次作業沒有什麼改動。

bug解析

這一次強測和互測沒出bug,但是討論群裡別的同學分享bug的時候,我發現我出了同樣的bug。

舉例說明:輸入資料為 0 f(x,y)=x+y f(y,x),輸出2*x(這個資料樣例不合法,只是用來說明一下bug)

原因在於:對自定義函式帶入引數的時候,先把x換成了y,然後又把y,換成x,就是說我對替換進去的引數進行了替換。

修復bug:先把自定義函式表示式的x換成p1,y換成p2再進行替換。

度量分析

Hack策略

沒有寫程式生成資料,別人的程式碼太難看懂,所以隨手試了一些資料,跟上次的區別在於,OS學了指令碼,我先把別人的程式生成Jar包,再寫了一個簡單的指令碼,用git bash命令列進行的測試,以前都是在IDEA裡面比對輸出結果。只發現一個同學sin((-x))輸出sin(-x)的bug

心得體會

  1. 學習到了遞降法,或者說是層次化。遞降法我認為麻煩的地方在於兩個方面

    • 一個是我怎麼降到下一個層次。

      就這次作業說就是怎麼從表示式裡面識別提出一個一個的項,怎麼從項裡面識別提出一個一個的因子。

    • 一個是我怎麼用下一個層次傳上來的結果得出我這一個層次的結果。

      舉例說怎麼用項化簡得到的HashMap來得到表示式化簡的HashMap。

  2. 仔細閱讀指導書的要求再動手,要想好以後再動手,不要急著開始寫程式碼。

    實際上第一次作業對我來說是最難的,因為第一次需要從零去學習這個遞降的結構。我先花了一晚上看了訓練的題目,有了一些理解。然後又花了一個下午,想通了第一點裡面提到的兩個方面,這個時候我覺得可以開始寫程式碼了。然後又花了一些時間把各個因子的Pattern造出來。

    說這些是為了說明我認為設計是寫程式很重要的一步,我花了很久的時間去搞清楚遞降法是什麼,在想通之前覺得沒法動手,想通以後就覺得不是很難,因為清晰的架構有了,接下來就是繁瑣的但是不是很難的東西。