現代程序設計 homework-10

通過大半學期的學習和練習, 咱們把學到的東西綜合起來。

經過<現代程序設計>這門課,本身的確學到了好多東西.其實並非說講課有多棒,一是由於講課的次數其實並很少,二是講課的內容其實感受並無太大的提升,在課程快結束的時候,我如今還可以有記憶的知識性內容,也許只有C++11的一點點知識.可是之因此說經過這門課本身學到了好多,是由於這門課佈置的做業和這門課一塊兒上課的同窗.javascript

先說做業,回顧之前作過的做業css

閒來無事統計了一下做業的有效代碼量html

記得這門課剛開始的時候老師發了一張表統計你們目前的代碼量...由於剛剛參加完暑期ACM集訓....本身很囂張的填了五萬行...如今看來真的是Too Simple,Sometimes Naive....前端

 

對於不一樣的人來講,這些做業的意義可能不一樣,對於如今正渴望學習不少東西的我來講,這些做業讓我掌握了許多.從最初的動態規劃解決各類子數組問題,到一步步的製做UI作成類庫實現單例模式作成一個簡單的軟件,從解決看起來不可能的word search到利用TCP完成服務器/客戶端鏈接處理用戶提交數據並實現動態展示黃金數,再到讀懂千行程序完成註釋並嘗試添加新功能修改Bug,還有此次的利用網頁腳本編程學習JavaScript,經過這大大小小十次做業,語言方面熟練了C#,學會了JavaScript,瞭解了C++11,方法方面熟悉了單元測試,單例模式,學習了C#和C++的網絡通訊內容java

再說一塊兒上這門課的同窗,都是早已聞達於諸侯的骨灰級大神人物,這樣的氛圍也驅使本身能夠不斷的去學習進步git

 

 

關於本次做業

本次做業要求寫成一個網頁可以直接在網上顯示,開始的時候我想用ASP.NET來實現,正好能夠藉此機會學習一下,在基本掌握了ASP.NET的初步實現方式以後,我開始糾結於如何在網上直接顯示,很明顯我須要申請域名放個人前端網頁,而後再配個人後臺進行用戶輸入處理(不知道是否是這個樣子)....好麻煩..後來瞭解了一下JavaScript以後發現這個東西應該能夠很輕鬆的解決個人這個需求,因而整個程序我最終採用JavaScript來實現,沒有采用任何相似於JQuery的庫,一是由於用原始的JS語言能夠更好的瞭解其DOM模型,二是其實我當時不知道有JQuery這個庫...github

 

 

 

 

在做業2 (http://www.cnblogs.com/xinz/p/3318230.html ) 中, 同窗們用各類方法 (主要是動態規劃,外加一些遍歷)計算了一維和二維數組中最小最大子數組的和。 固然,程序在飛快地運行的時候,咱們能夠經過debug 工具中的 單步執行 命令看到中間結果。 中間結果通常有這些數據:

這個數組目前暫定的最大子數組的範圍是哪裏?  目前的值是多少?

目前計算到哪些部分, 目前的牽涉到的子數組的和是多少?

咱們的要求是,設計並實現一個系統,讓一個普通用戶就能經過單步執行的方式看到你的算法是如何工做的。

 

一個典型的流程是:

1. 用戶用你的程序讀入一個數組文件 (就像咱們之前作過的那樣),顯示初始狀態 (就像圍棋打譜程序那樣)

這裏當用戶單擊"輸入指定按鈕"這個Button以後,會按照用戶輸入的行列要求產生指定的表格,用戶能夠輸入數組文件算法

主要實現方法是根據用戶輸入不停的在DOM這個模型樹上添加標籤<tr><td>子標籤,在用戶輸入數組以後利用正則文法進行輸入正確性有效性檢查,而後將輸入內容導入計算數組中,最終在網頁端顯示初始狀態數據庫

1.1. 用戶也能夠自行定義數組的大小,或者要求隨機生成一個數字矩陣。

這裏當用戶單擊"生成隨機數組"這個Button以後,會按照用戶輸入的行列要求產生隨機數組編程

主要實現方式是根據用戶輸入產生相應表格以後,利用隨機數產生相應數字,例如我要產生-1000~1000之間的整數,那麼就能夠利用下面的一行代碼來實現

1 Math.floor(Math.random() * (2000) - 1000)

 

2. 用戶這時候有兩個選擇

2.1  按 單步執行 鍵, 在 GUI 看到你的程序是如何一步一步算出目前最大子數組的範圍,當前計算到的臨時子數組是在哪裏,等等。 最好用不一樣的顏色標識不一樣的狀態。

這裏當用戶選擇"單步執行"這個RadioButton以後,用戶能夠按">>"鍵一步一步看到演示,當前計算到的臨時子數組會以紫色區域顯示,當前的最大子數組會以白邊區域顯示

主要實現方式是事先計算好整個動態規劃過程當中的每一個狀態.例如我能夠用一個二維數組來記錄,第一維表示當前的狀態序號,第二維利用當前整個數組的01組合來表示.關於01組合表示,我想到了兩個方法,第一個是第二維大小等於row*col,這樣每個(i,j)座標均可以根據公式i*col+j表示成一個下標,而後用01來表示;第二個是能夠利用位運算實現狀態壓縮,將每一個(i,j)利用位運算壓縮成一個長度爲row*col字符串.相比較而言,位運算效率更高. 

單步執行過程當中,每次展現當前的狀態序號表示的狀態,其中爲了不顏色衝突的問題,我用紫色來表示當前正在計算的子數組,白邊區域表示目前位置已經算出的最大子數組.整個界面的配色方案採用win8的Metro配色風格.

2.2  按 自動運行 鍵, 在 GUI 看到程序自動運行,並自動顯示過程, 每次改變狀態的時候要稍做停留 (例如 1 秒鐘的時間)

這裏當用戶選擇"自動運行"這個RadioButton並設置好Interval以後,程序會按照用戶自定義的Interval一步一步執行,在每次改變狀態的時候會停留相應間隔

不得不說JavaScript對於計時器的支持其實頗有限,SetTimeout()和SetInterval()兩種方法.我才用SetInterval(),第一個參數傳遞我改變狀態的這個函數AutoRunning(),並在當前狀態序號超過狀態總數的時候clearInterval()中止個人當前計時器,第二個參數傳遞用戶自定義的Interval屬性.

3. 咳,我沒看清楚!  這時最好有一個 倒帶 / 回滾 的鍵, 讓用戶能夠看清楚關鍵的幾步。

這裏用戶能夠隨時按"Pause"按鈕暫停自動運行,並能夠隨時切換自動/手動模式,前進或者後退

這個實現起來也很簡單,倒帶/回滾就是返回上一個狀態

(固然,用戶能夠選擇是普通模式仍是擴展定義的連通模式)

下面的邏輯選項分別有一維/二維/水平相連/垂直相連/水平垂直都相連/聯通塊/水平垂直相連聯通塊等模式,用戶能夠自由選擇

 

對於一維和二維普通模式我採用了普適的動態規劃算法,對於水平相連的狀況我是採用我在第二次做業中提到的方法:

對於一維左右聯通狀況,咱們能夠知道它的最大和要麼是沒有跨過了a[n]和a[1],要麼是沒有跨過;若是沒有跨過,那麼就是簡單的一維普通狀況,記最大值爲ans1;若是跨過了,那麼不妨設此時的最大子數組爲a[j],a[j+1],....a[n],a[1],a[2],...a[i],i<j,此時能夠證實a[i],a[i+1],....a[j]必定是最小子數組,而且a[i]和a[j]必定是小於0的(不然能夠加到最大子數組中獲得更優的解),那麼咱們掃描一遍的時候,只要同時記錄最大子數組,最小子數組,和數組總和,那麼ans=max(ans1,all-ans2);

而與二維垂直相連狀況,其實和二維普通狀況是同樣的,只不過循環的時候枚舉縱向開始和結束的時候不須要保證結束點>開始點就好,同時要根據不一樣的開始/結束關係指定不一樣的染色方案

對於聯通塊的幾種狀況,我仍是用了狀壓dp的樸素解決方法,展現起來相似於枚舉,因此能夠處理的狀態數有限,我在程序中也作了限制,用戶輸入的row*col的值不能超過16,這樣對於O(m*n*2^mn)的複雜度來講,已經算是能夠勉強接受了.

要求: 這個要求的各個方面咱們都已經單獨寫代碼試驗過了,把它們合起來也不是太難。

寫JavaScript仍是遇到了一些問題,JS是一門弱類型的語言,因此在進行運算的時候稍不注意就會發生字符串鏈接的狀況,這在前期致使我debug了很久.另外對於這樣一門腳本語言,直接在網頁端debug貌似不是那麼方便...

 最終個人頁面用Index.html來顯示

Declaration.js用來定義一些基本的全局變量(全局變量這種東西雖然很危險,但對於這樣一個小型的項目來講的確很方便)

BaseFunction.js用來處理用戶輸入,獲得數組與行列等基本參數

Check.js用來檢驗用戶各類輸入有效性,採用正則文法來驗證

MaxSum.js用來處理程序邏輯,處理求最大子數組的過程

State.js用來改變展現狀態

ButtonEvent.js用來處理各類控件響應事件

 

 

要求還那樣: 寫程序和單元測試,簽入GitHub,寫博客描述,總結所花費的時間和估計。

程序已經導入GitHub.https://github.com/oldoldb/homework-10

 

每次的總結所花費的時間和估計都是特別水的事情,由於一開始對於所要學習的知識和做業沒有很好地瞭解,沒法準確估計時間,而真正開始編碼的時候又會太過投入忘記記錄花費時間..

因此如下又是複製粘貼之前的....

  Personal Software Process Stages 時間百分比(%)  實際花費的時間 (分鐘) 原來估計的時間 (分鐘)
Planning 計劃 2.0  45            60 
·         Estimate  ·         估計這個任務須要多少時間,把工做細化並大體排序 2.0  45 60 
Development 開發 88.7  2000  1500
·         Analysis  ·         需求分析 (包括學習新技術) 2.7  60  60
·         Design Spec ·         生成設計文檔   0  0
·         Design Review ·         設計複審 (和同事審覈設計文檔) 0  0  0
·         Coding Standard ·         代碼規範 (制定合適的規範) 5.3  120  60
·         Design ·         具體設計 5.3  120  60
·         Coding ·         具體編碼 62.1  1400  1200
·         Code Review ·         代碼複審 10.6  240  60
·         Test ·         測試(自咱們測試,修改代碼,提交修改) 2.7  60  60
Reporting 總結報告 9.3  210  60
·         Test Report ·         測試報告 5.3  120  0
·         Size Measurement ·         計算工做量 1.3  30  0
·         Postmortem & Improvement Plan ·         過後總結, 並提出改進 2.7  60  60
Total 總計 100% 總用時 總估計的用時
       2255  1260

 

評分:

功能 (分數範圍 –30 到 30分):  在PC 桌面上運行  (滿分 20 分); 若是能在程序能直接在網上顯示 (例如使用 Javascript 在網頁上讓用戶直接看到過程),則滿分是 30 分。

我採用的是Html+CSS+JavaScript,程序能夠直接在網上顯示,滿分30分.

 

代碼質量 (分數範圍:  -30 分到 30 分):  同窗們在課程中已經看了不少書,實踐了很多原理,也看過爛的代碼 (不少同窗還大義凜然地鄙視過爛代碼),而且紛紛表示要寫高效/好懂/可擴展的算法。如今就來試試看,請寫博客,截圖,畫圖描述:

首先我沒有看不少編碼規範方面的書,這學期爲了這門課學習的書有<編程之美>,<數學之美>,<C#方面的書>,<Windows Form方面的書>,WPF方面的書>,<Visual C#網絡編程方面的書>,<WinSock編程方面的書>,<Asp.net方面的書>,<JavaScript方面的書>,代碼大全這本書老師雖然推薦可是其實並無讀...也許這就是短視吧...畢竟就這門課目前來講可能追求的短平快..

 

    註釋,命名: 有一致規範的規範,合適的註釋  

  個人代碼的命名和註釋一貫都比較完成和規範,命名規範已經逐漸過渡到帕斯卡命名法,註釋也會隨手寫好

  命名方面我比較傾向於用有意義的完整單詞來表示函數/變量的意義,例如CreateTable,InitSum等等,不太支持用簡寫來表明整個單詞,由於這樣常常會出現簡寫含義不清楚,並且不

  同的人對於同一個單詞的簡寫方法理解不一樣,而用完整單詞不會出現這個問題.對於Button事件我都同一用ButtonName+Clicked來表示等等

  

  

    結構: 結構清晰,各類類/結構的定義 正確地反映了現實世界實體,以及實體之間的關係.

  多是對於JS的編碼經驗不夠,JavaScript定義成類我的感受徹底沒有必要,我定義許多function須要的時候就用就好..

  程序結構以下:

  

  此次用的純JavaScript實現,沒有使用JQuery庫,對本身也是一個鍛鍊,邏輯放在.js裏實現,.css實現樣式表,.html用於基本構建頁面.

    單元測試: 有單元測試保證 非UI 模塊的正確性  (UI 模塊不要求單元測試自動覆蓋),有代碼覆蓋率。

  咱們的授課老師鄒老師不愧是單元測試之王,C++/C#咱們要作單元測試,此次的腳本也要作單元測試.

  JavaScript的單元測試我採用QUnit,這個單元測試框架主頁在這裏:http://qunitjs.com/

  因爲不少地方不方便作單元測試,對於非UI模塊,我挑選了MaxSum(b,n),MinSum(),CheckMargin(x,y)三個典型的函數就行單元測試,測試以下:

 1 test("Test for MaxSum(b,n)",function()
 2 {
 3     var testArray = new Array(10, -1, -10, 10, 2);
 4     var ActualResult=MaxSum(testArray,5);
 5     equal(ActualResult, 12, "MaxSum(testArray,5) is 12");
 6     testArray = new Array(-10, -10, -10, -10, -100);
 7     ActualResult = MaxSum(testArray, 5);
 8     equal(ActualResult, -10, "MaxSum(testArray,5) is -10");
 9 })
10 test("Test for MinSum(b,n)",function()
11 {
12     var testArray = new Array(10, -1, -10, 10, 2);
13     var ActualResult=MinSum(testArray,5);
14     equal(ActualResult, -11, "MinSum(testArray,5) is -11");
15     testArray = new Array(-10, -10, -10, -10, -100);
16     ActualResult = MinSum(testArray, 5);
17     equal(ActualResult, -140, "MinSum(testArray,5) is -140");
18 })
19 test("Test for CheckMargin(x,y)",function()
20 {
21     var row=10;
22     var col=5;
23     var ActualResult=CheckMargin(10,5);
24     equal(ActualResult, false, "CheckMargin(10,5) is false");
25     ActualResult = CheckMargin(-1, -1);
26     equal(ActualResult, false, "CheckMargin(-1,-1) is true");
27 })
 1 <!DOCTYPE html>
 2 
 3 <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
 4 <head>
 5     <meta charset="utf-8" />
 6     <title></title>
 7     <script type="text/javascript" src="QUnit.js"></script>
 8     <script type="text/javascript" src="homework-10.js"></script>
 9     <script type="text/javascript" src="test.js"></script>
10     <link href="QUnit.css" rel="stylesheet" type="text/css" />
11 </head>
12 <body>
13     <h1 id="qunit-header">QUnit Test Suite</h1>
14     <h2 id="qunit-banner"></h2>
15     <div id="qunit-testrunner-toolbar"></div>
16     <h2 id="qunit-userAgent"></h2>
17     <ol id="qunit-tests"></ol>
18     <div id="qunit-fixture">test markup</div>
19 </body>
20 </html>

 

  咱們能夠看到有一個點沒有過,當我輸入的數組爲爲(-10,-10,-10,-10,-100)時,我指望獲得的子數組最大和爲-10,但結果確實測試不正確,但實際運行的結果:

因此我以爲多是一些全局變量單元測試不能很好地照顧到,致使出現了這一問題...

 

關於代碼覆蓋率,JS的代碼覆蓋率檢查我在網上搜到使用ScriptCover來實現,可是這東西貌似down不下來?並且對於單元測試這種東西個人意見一貫是這種東西是對於大型項目封裝的很完全才能發揮它的做用,而對於一些小型項目來講,無謂的刷代碼覆蓋率是沒有多少實際意義的...

(注:  以上的各個部分,達不到基本要求的,倒扣分,扣到 –30 分爲止。 抄襲按學校規定處理)

 

我不會達不到基本要求嗒

 

附加題:  你已經作了這麼多,不妨再進一步: 若是博客中描述了動態規劃的原理,並經過錄製屏幕的方式讓通常的讀者 (例如,正在學習算法的大學生)能經過你的動態程序理解動態規劃的算法,以及這個算法的擴展,那麼能夠獲得附加分  10 分。你能夠宣傳你的博客,讓你們都來學習。 

 

"你已經作了這麼多,不妨再進一步".......

動態規劃,維基百科上的原理解釋是這樣的

就個人理解來講,動態規劃主要有兩點:

1.最優子結構

2.重疊子問題

最優子結構保證了咱們能夠利用動態規劃來解決問題,而重疊子問題保證了咱們能夠獲得比樸素方法複雜度更低的算法.

我在暑假的時候較爲系統的學習過算法,當時影響我比較深的兩篇博客推薦在這裏:

第一個是July大神的博客,他的博客不用多說已經被不少人拜讀過了:http://blog.csdn.net/v_july_v/article/details/6110269

第二個是liufeng_king的博客,他的博客基本上系統的闡述了大二下學期算法課本的內容:http://blog.csdn.net/liufeng_king/article/details/8490770

關於動態規劃的知識點研究方法相信能夠在以上兩篇博客中找到答案.

 

在這裏咱們利用最大子數組問題探討一下動態規劃算法

 

題目描述:輸入一個整型數組,數組元素有正有負,數組中連續的一個或多個整數組成一個子數組,求全部子數組的和的最大值.

樣例:例如輸入的數組爲-10,-1,1,2,-10,那麼最大的子數組和爲1+2=3

動態規劃解法:

記原數組爲a[i],sum[j]=max{a[i]+a[i+1]+...+a[j]},0<=i<=j,且0<j<n,那麼所求的最大子數組和爲max{sum[j]},0<=j<n

那麼咱們很容易知道,當sum[j-1]>0時,sum[j]=sum[j-1]+a[j],(由於a[j]加上一個正數總會大於自身的),不然sum[j]=a[j],(由於a[j]加上一個負數確定比自身小) 注意咱們的sum[j]的含義,它表明j之前的最大子數組和.

那麼咱們能夠獲得動態規劃方程爲

sum[j]=max(sum[j-1]+a[j],a[j]),0<=j<n,

已知遍歷一遍數組,同時維護一個最大ans,便可獲得答案.複雜度爲O(n)

 

當咱們將數組擴展到二維,只需在進行動態規劃以前,先將數組縱向壓縮爲一維就好,關於擴展的算法能夠參見我之前的做業:http://www.cnblogs.com/oldoldb/p/3331975.html

至於聯通塊問題,目前個人解決方式仍是停留在暴力狀壓DP的解決層面上...

 

下面根據咱們的演示程序演示一下最大子數組的求解方法:

咱們先隨機生成一個一維數組,ans初始化爲-Number.MAX_VALUE

此時掃描第0個元素,當前計算子數組爲a[0]=-789,暫定最大和=sum[0]=a[0]=-789,ans=max(ans,sum[0])=ans=sum[0]=-789

掃描第1個元素,當前計算子數組爲a[1]=523,sum[1-1]=sum[0]=-789<0,因此暫定子數組=sum[1]=a[1]=523,ans=max(ans,sum[1])=523

掃描第2個元素,當前計算子數組爲a[2]=-779,因爲sum[1]=523>0,因此sum[2]=sum[1]+a[2]=-256,ans=max(ans,sum[2])=523

a[3]=788,sum[2]<0,sum[3]=a[3]=788,ans=max(ans,sum[3])=788

依次類推

掃描最後一個元素,咱們獲得最大子數組和(白邊區域)ans=2443.

這個演示程序是否是很方便~!若是有任何地方不清楚能夠隨時後退~

以上示例生成的GIF演示以下

 

 

 

 

感受最後一次做業作的比較完美了.

現代程序設計是一門很好的課,

這個學期有編譯/數據庫/軟工這三門親手寫項目的課,並且工程量都不小,

可是我仍是認爲現代程序設計帶給個人收穫更大

那麼,

現代程序設計,

再見!

相關文章
相關標籤/搜索