概要:
这次作业老师要求我们做一个算法演示程序。演示求子矩阵,使得总和最大。
关于这次程序的要求,做网页版能够有更高的评价,所以我就果断做了网页版。并且,可能很多人觉得服务器、客户端是最有效的手段。可是,我这一次使用了纯html+css+javascript实现,不需要任何的服务器端,只要有一个稳定的浏览器,就可以进行算法演示,页面加载完后,即使断开网络,也能继续完整地进行算法演示。
另外,作业中有个10分附加部分,录制屏幕作演示,这个我也完成了。使用windows自带的步骤记录器,psr.exe。上传到了百度云盘上:
http://pan.baidu.com/s/1pbAtZ
首先是主界面:
(这个程序符合w3c规范,在mac系统下的safari、firefox,windows系统下的IE、firefox都完整地测试通过,本次演示使用mac下的firefox)
从中,我们可以大概看到程序的功能,以下是其特性:
1.点击行数以后,文本框中文字会自动消失,让用户进行登录,更加直观
2.根据输入的行数和列数,矩阵文本区域会自动放大、缩小,以给用户一个适合的文本区域进行输入
3.能够选择连通性,根据不同的连通方法进行不同的计算。
4.能够根据当前的行和列,生成随机输入
当输入完成后,我们就能进入到计算过程了:
其中,红色区域是当前正在计算的区域,蓝色区域是目前已找到的和最大的区域,紫色就是红色和蓝色的重叠。
本算法使用的是积分图进行求和运算,理所当然,应该要有个显示积分图的功能:
从中,我们看到功能区的功能是根据当前情况动态变化的。
算法中,我们设左上角的点为P1,右下角的点为P2。在这个算法调试中,我们需要3种功能:
1.单步执行
2.设置断点
3.自动执行
首先是单步执行,这又分为两种情况,第一种是让P1向下移动1格,第二种是让p2向下移动一格。这理所当然地都被支持了:
另外就是自动执行,下方就可以输入每步间隔,支持暂停与继续,点击开始就行(执行时候也能修改间隔时间也能自动调整)。算法结束时,也会自动给出提示:
另外一个功能就是设置断点,经过努力,这个演示程序提供了极其简洁易懂地方式。可以直接用鼠标选择运行到地位置:
鼠标点击后,类似右键菜单,可以选择P1或者P2移动到当前位置,并且这个界面当鼠标移走后会自动消失,十分美观、实用。
关于代码实现:
本程序地所有动态效果都是纯javascript实现。并且整个运算过程都是javascript动态生成的。本程序在单页面上实现了这所有的工作,不需要服务器支持。对于我来说是一次挑战,做出这个的时候我也感到成就感十足。
运算过程其实是一次迭代。输入期望停止的点,然后循环开始,到期望点后自动退出循环:
function step(t_x1, t_y1, t_x2, t_y2) //参数是希望停止的位置 {for (; x1<=maxx; x1++) {if (y1>maxy) {y1 = 1;}for (; y1<=maxy; y1++) {if (x2==tx && y2==ty) {x2 = x1;y2 = y1;}if (hflag) { //hflag是纵向连通标记tx = x1+maxx-1;} else {tx = maxx;}if (vflag) { //vlag是横向连通标记ty = y1+maxy-1;} else {ty = maxy;}if (x2>tx) {x2 = x1;}for (; x2<=tx; x2++) {if (y2>ty) {y2 = y1;}for (; y2<=ty; y2++) {tmax = inte[x2][y2]+inte[x1-1][y1-1]tmax = tmax-inte[x2][y1-1]-inte[x1-1][y2]if (tmax > res_max) //找到更优解 {res_x1 = (x1-1)%maxx+1;res_y1 = (y1-1)%maxy+1;res_x2 = (x2-1)%maxx+1;res_y2 = (y2-1)%maxy+1;res_max = tmax;}if (x1==t_x1&&y1==t_y1&&x2==t_x2&&y2==t_y2) { //如果到达了停止点 showAll();if (y2==ty&&x2==tx&&y1==maxy) {x1 = x1 + 1;y1 = 1;x2 = x1;y2 = y1;}if (y2==ty&&x2==tx) {y1 = y1 + 1;x2 = x1;y2 = y1;}if (y2==ty) {x2 = x2+1;y2 = y1;}return;}}}}}showAll(); //如果全都运行完了,也需要刷新一下。 }
程序的流程。首先显示的输入页面,是一个html页面,加上各种javascript效果。主要处理的是文本框的输入、矩阵文本区域大小的自动调整、随机矩阵的生成。
随机矩阵生成也十分简单,代码如下:
$("#random").click(function () {var x = $("#x").val();var y = $("#y").val();s = "";var i, j, t;for (i=1;i<=x;i++) {for(j=1;j<=y;j++) {t = Math.round(Math.random()*200)-100;s = s + t + "\t";}s = s + '\n';}$("#m").val(s);})
将待生成的矩阵变成一个字符串重写文本区域内容即可。
点击提交按钮后,程序自动算出演示算法需要区域的大小,以及对应矩阵、积分图数据,供下面算法部分使用。代码如下:
$("#calc").click(function () {var i, j, s;maxx = parseInt($("#x").val());maxy = parseInt($("#y").val());s = $("#m").val();s = s.replace(new RegExp('\t', 'g'), " ");s = s.replace(new RegExp('\n', 'g'), " ");s = s.split(" ")var sArray = new Array()for (i=0; i<s.length;i++) {if (s[i]!="") {sArray.push(s[i]);}}for (i=0;i<=2*maxx;i++) {m[i] = new Array();inte[i] = new Array();for (j=0;j<=2*maxy+1;j++) {if (i==0||j==0) {m[i][j]=0;inte[i][j]=0;} else {if (i>maxx || j>maxy) {m[i][j] = m[(i-1)%maxx+1][(j-1)%maxy+1];} else {m[i][j] = parseInt(sArray[maxy*(i-1)+j-1]);}inte[i][j] = m[i][j]+inte[i-1][j]+inte[i][j-1]-inte[i-1][j-1];}}}$(document.body).html("");init();draw();showAll();showTools();})
至于算法页面,就是一个javascript函数画出来的,每个功能都是动态修改页面得到的效果。一下是初始化页面内容函数:
function draw() {var tstr="";tstr = tstr + ("<div id=data>")tstr = tstr + ("<div id=m><h1>数据矩阵</h1><table border=1>")for (i=0;i<=maxx;i++) {tstr = tstr + ("<tr>\n");for (j=0;j<=maxy;j++) {var t_id = i*(maxy+1)+jif (i==0&&j==0) {tstr = tstr + ("<th class=tHead>")tstr = tstr + ("行\\列");tstr = tstr + ("</th>\n");} else if (i==0 || j==0){tstr = tstr + ("<th class=tIndex>")if (i == 0) {tstr = tstr + (j);} else {tstr = tstr + (i);}tstr = tstr + ("</th>\n");} else {tstr = tstr + ("<td id=\"mat"+t_id+"\" οnclick=\"showPopUp(event, "+t_id+")\">")tstr = tstr + (m[i][j]);tstr = tstr + ("</td>\n");}}tstr = tstr + ("</tr>\n");}tstr = tstr + ("</table></div>")tstr = tstr + ("<div id=inte><h2>积分图</h2><table border=1>")for (i=0;i<=maxx;i++) {tstr = tstr + ("<tr>\n");for (j=0;j<=maxy;j++) {var t_id = i*(maxy+1)+jif (i==0&&j==0) {tstr = tstr + ("<th class=tHead>")tstr = tstr + ("行\\列");tstr = tstr + ("</th>\n");} else if (i==0 || j==0){tstr = tstr + ("<th class=tIndex>")if (i == 0) {tstr = tstr + (j);} else {tstr = tstr + (i);}tstr = tstr + ("</th>\n");} else {tstr = tstr + ("<td id=\"inte"+t_id+"\" οnclick=\"showPopUp(event, "+t_id+")\">")tstr = tstr + (inte[i][j]);tstr = tstr + ("</td>\n");}}tstr = tstr + ("</tr>\n");}tstr = tstr + ("</table></div>");tstr = tstr + ("</div><div id=vars>")tstr = tstr + ("<div id=current><p>当前考察区域</p>");tstr = tstr + ("<p id=x1>1</p>");tstr = tstr + ("<p id=y1>2</p>");tstr = tstr + ("<p id=x2>3</p>");tstr = tstr + ("<p id=y2>4</p>");tstr = tstr + ("<p id=tmax>10</p>");tstr = tstr + ("</div>");tstr = tstr + ("<div id=current><p>目前最优区域</p>")tstr = tstr + ("<p id=res_x1>5</p>");tstr = tstr + ("<p id=res_y1>6</p>");tstr = tstr + ("<p id=res_x2>7</p>");tstr = tstr + ("<p id=res_y2>8</p>");tstr = tstr + ("<p id=res_max>9</p>");tstr = tstr + ("</div>");tstr = tstr + ("<p id=hflag>10</p>");tstr = tstr + ("<p id=vflag>10</p>");tstr = tstr + ("<div id=panel><h2>操作区</h2><div id=tools></div></div>");tstr = tstr + ("</div>");$(document.body).html(tstr);$("#inte").hide(); //默认隐藏积分图 }
以上就是核心思想,具体代码及完整注释都已签入github。
助教辛苦了!