现代程序设计 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演示以下

 

 

 

 

感受最后一次做业作的比较完美了.

现代程序设计是一门很好的课,

这个学期有编译/数据库/软工这三门亲手写项目的课,并且工程量都不小,

可是我仍是认为现代程序设计带给个人收获更大

那么,

现代程序设计,

再见!

相关文章
相关标签/搜索