homework-02
关于输入
先来说说关于输入的事情。其实我最一开始并没有发现输入数字之间是用逗号隔开的,所以我是当做空格隔开来写的,后来发现以后匆忙改正,利用strtok与atoi函数从字符串中提取出用逗号隔开的数字。由于作业中的要求说任何输入错误都不能使我的程序崩溃,所以所有与输入有关的地方都加了一个判断,发生错误时将对应的错误打印出来并结束程序。这是输入部分的代码:
if(fgets(buf, 256, in) == NULL){
printf("ERROR: file input error\n");
return 0;
}
h = atoi(buf);
if(h == 0 && buf[0] != '0'){
printf("ERROR: file input error\n");
return 0;
}
if(fgets(buf, 256, in) == NULL){
printf("ERROR: file input error\n");
return 0;
}
l = atoi(buf);
if(l == 0 && buf[0] != '0'){
printf("ERROR: file input error\n");
return 0;
} num = (int **)malloc(h * sizeof(int));
for(i = 0; i < h; i++)
num[i] = (int *)malloc(l * sizeof(int));
for(i = 0; i < h; i++){
if(fgets(buf, 256, in) == NULL){
printf("ERROR: file input error\n");
return 0;
}
for(j = 0; j < l; j++){
p = (j == 0 ? strtok(buf, ",") : strtok(NULL, ","));
if(p == NULL){
printf("ERROR: file input error\n");
return 0;
}
num[i][j] = atoi(p);
if(num[i][j] == 0 && p[0] != '0'){
printf("ERROR: file input error\n");
return 0;
}
}
}
关于算法
我的算法是从之前的一维算法扩展而来的。首先我解决的是最普通情况下的二维数组,我是这样想的:首先确定一个子矩阵的上下边界,这样子的话,上下边界之间的每一列之和就可以看做一个数,然后就可以利用一维数组的方法在O(n)时间内找出此时确定的上下边界的最大子矩阵的和,关于一维算法可以查阅我的上一篇博客:链接。这样我们利用一个嵌套的循环将上下边界扫描一遍,于是通过比较就得出了整个二维数组的最大子数组的和,时间复杂度是O(n^3)。这是最初的功能代码:
for(i = 0; i < h; i++){
for(j = i; j < (isv ? h+i : h); j++){
super = num[0][0];
for(m = 0; m < (ish ? l : 1); m++){
max = sum(h, l, i, j, m, num);
maxend = max;
tmpsum = sum(h, l, i, j, k, num);
maxend = maxend+tmpsum > tmpsum ? maxend+tmpsum : tmpsum;
max = max > maxend? max : maxend;
}
super = super > max ? super : max;
}
}
可是/h和/v怎么办呢?我在程序中对应功能部分都增加了对应的独立的判断,以面对功能的要求。因为我将/v与/h的判断完全放在主功能代码中,而且两者完全独立互不干扰,这样就保证了当两个参数同时存在时也不需要改变代码就可以支持,而且参数的位置变化也没有影响。具体先来看/v好了,/v表示二维数组在垂直方向是首尾相连的。我的做法是在跳出循环的边界判断中增加一个判断,如果/v那么下边界一直循环到起始边界加上总行数,在计算和时如果遇到大于等于行数的数字就减去行数,这样就做到了从下边界一直从起始边界一直循环到起始边界的上一行,也就是保证了竖直方向的首尾互联。如果有/h的话在水平方向的首尾相连也使用相同的处理方法,所不同的是,原来在水平方向只要进行一次O(n)的扫描就可以了,但是如果首尾相连了,为了找出最大的值,那么需要将每一列作为起点扫描一次,也就是说水平方向的扫描需要再加一层循环也就是O(n^2)的复杂度,那么整个算法就变成了O(n^4)的复杂度。如果同时有/v与/h则不需要改变算法直接进行计算。支持/v与/h的功能代码如下:
ult = num[0][0];
for(i = 0; i < h; i++){
for(j = i; j < (isv ? h+i : h); j++){
super = num[0][0];
for(m = 0; m < (ish ? l : 1); m++){
if(!sum(&max, h, l, i, j, m, num)){
printf("ERROR: int overflow\n");
return 0;
}
maxend = max;
for(k = m+1; k < (ish ? l+m : l); k++){
if(!sum(&tmpsum, h, l, i, j, k, num)){
printf("ERROR: int overflow\n");
return 0;
}
if((maxend > 0 && tmpsum > 0 && (maxend+tmpsum <= maxend || maxend+tmpsum <= tmpsum)) || (maxend < 0 && tmpsum < 0 && (maxend+tmpsum >= maxend || maxend+tmpsum >= tmpsum))){
printf("ERROR: int overflow\n");
return 0;
}
maxend = maxend+tmpsum > tmpsum ? maxend+tmpsum : tmpsum;
max = max > maxend ? max : maxend;
}
super = max > super ? max : super;
}
ult = super > ult ? super : ult;
}
}
关于溢出
由于需要考虑溢出,那么在程序中所有用到加法运算的地方都需要判断,那么我将sum函数改进了一下,它的返回值不再是运算结果,而是是否正确进行运算,成功则返回1,返回0表示发生了溢出,运算结果有指针传入到主函数中,同时在主函数中的运算加上了溢出判断,判断的方法是这样子的:如果相加的两数都为正并且其中至少有一个数比和还大,或者相加两数都是负数并且其中至少有一个数比和还小,那么说明发生了溢出。发生溢出之后打印出溢出错误并结束程序。改进后的sum函数如下:
int sum(int *tmpsum, int h, int l, int i, int j, int k, int **num){
int a, tmpnum, s = 0;
*tmpsum = 0;
for(a = i; a <= j; a++){
tmpnum = num[(a >= h ? a-h : a)][(k >= l ? k-l : k)];
s = *tmpsum + tmpnum;
if((*tmpsum > 0 && tmpnum > 0 && (s <= *tmpsum || s <= tmpnum)) || (*tmpsum < 0 && tmpnum < 0 && (s >= *tmpsum || s >= tmpnum)))
return 0;
*tmpsum = s;
}
return 1;
}
关于设计
我的设计中所有功能都在同一个功能块中完成,每一种不同的功能都有对应的判断,而每一种功能之间相互独立互相不影响,这就保证了我的程序能利用一个功能块完成所有的功能,所以我在分别完成/v与/h的同时也完成了/v、/h同时存在的情况。这种结构方式虽然不清晰,但是在这种短小的程序中还是非常实用的。
关于感想
恕我愚昧到现在为止实在是无法写出/a的算法,我思索了很久,最终还是选择了放弃,所以在现在的程序中如果在命令行中输入参数/a则会打印出错误,错误原因是程序目前不支持/a。还有关于单元测试与代码覆盖率的问题,由于我的代码完全是用C语言写的,我暂时还不知道如何利用Visual Studio 2012作C语言这种面向过程程序的单元测试,所以这部分暂时空缺,待日后弄清楚以后补上。此次作业给我最大的感想就是/a的实现真的真的真的好难啊,完全超出了我能够驾驭的范围。
完整的源码
#include<stdio.h>
#include<stdlib.h>
#include<string.h> int sum(int *tmpsum, int h, int l, int i, int j, int k, int **num){
int a, tmpnum, s = 0;
*tmpsum = 0;
for(a = i; a <= j; a++){
tmpnum = num[(a >= h ? a-h : a)][(k >= l ? k-l : k)];
s = *tmpsum + tmpnum;
if((*tmpsum > 0 && tmpnum > 0 && (s <= *tmpsum || s <= tmpnum)) || (*tmpsum < 0 && tmpnum < 0 && (s >= *tmpsum || s >= tmpnum)))
return 0;
*tmpsum = s;
}
return 1;
} int main(int argc, char *argv[]){
int h, l, i, j, k, m, max, maxend, **num, ult, super, tmpsum, isv = 0, ish = 0;
char buf[257], *p;
FILE *in;
for(i = 1; i < argc-1; i++){
if(!strcmp(argv[i], "/v"))
isv = 1;
else if(!strcmp(argv[i], "/h"))
ish = 1;
else if(!strcmp(argv[i], "/a")){
printf("ERROR: \"/a\" not support yet\n");
return 0;
}
else{
printf("ERROR: command input error\n");
return 0;
}
}
if((in = fopen(argv[argc-1], "r")) == NULL){
printf("ERROR: file open failed\n");
return 0;
}
if(fgets(buf, 256, in) == NULL){
printf("ERROR: file input error\n");
return 0;
}
h = atoi(buf);
if(h == 0 && buf[0] != '0'){
printf("ERROR: file input error\n");
return 0;
}
if(fgets(buf, 256, in) == NULL){
printf("ERROR: file input error\n");
return 0;
}
l = atoi(buf);
if(l == 0 && buf[0] != '0'){
printf("ERROR: file input error\n");
return 0;
} num = (int **)malloc(h * sizeof(int));
for(i = 0; i < h; i++)
num[i] = (int *)malloc(l * sizeof(int));
for(i = 0; i < h; i++){
if(fgets(buf, 256, in) == NULL){
printf("ERROR: file input error\n");
return 0;
}
for(j = 0; j < l; j++){
p = (j == 0 ? strtok(buf, ",") : strtok(NULL, ","));
if(p == NULL){
printf("ERROR: file input error\n");
return 0;
}
num[i][j] = atoi(p);
if(num[i][j] == 0 && p[0] != '0'){
printf("ERROR: file input error\n");
return 0;
}
}
}
ult = num[0][0];
for(i = 0; i < h; i++){
for(j = i; j < (isv ? h+i : h); j++){
super = num[0][0];
for(m = 0; m < (ish ? l : 1); m++){
if(!sum(&max, h, l, i, j, m, num)){
printf("ERROR: int overflow\n");
return 0;
}
maxend = max;
for(k = m+1; k < (ish ? l+m : l); k++){
if(!sum(&tmpsum, h, l, i, j, k, num)){
printf("ERROR: int overflow\n");
return 0;
}
if((maxend > 0 && tmpsum > 0 && (maxend+tmpsum <= maxend || maxend+tmpsum <= tmpsum)) || (maxend < 0 && tmpsum < 0 && (maxend+tmpsum >= maxend || maxend+tmpsum >= tmpsum))){
printf("ERROR: int overflow\n");
return 0;
}
maxend = maxend+tmpsum > tmpsum ? maxend+tmpsum : tmpsum;
max = max > maxend ? max : maxend;
}
super = max > super ? max : super;
}
ult = super > ult ? super : ult;
}
}
printf("%d\n", ult);
}
关于这个表
Personal Software Process Stages |
时间百分比(%) |
实际花费的时间 (分钟) |
原来估计的时间 (分钟) |
|
Planning |
计划 |
|||
Estimate |
估计这个任务需要多少时间,把工作细化并大致排序 |
2 |
20 min |
10 min |
Development |
开发 |
|||
Analysis |
需求分析 (包括学习新技术) |
1 |
10 min |
20 min |
Design Spec |
生成设计文档 |
0 |
0 min |
0 min |
Design Review |
设计复审 (和同事审核设计文档) |
0 |
0 min |
0 min |
Coding Standard |
代码规范 (制定合适的规范) |
3 |
30 min |
20 min |
Design |
具体设计 |
11 |
100 min |
60 min |
Coding |
具体编码 |
32 |
300 min |
200 min |
Code Review |
代码复审 |
22 |
200 min |
150 min |
· Test |
测试(自我测试,修改代码,提交修改) |
120 min |
120 min |
|
Reporting |
总结报告 |
|||
· Test Report |
测试报告 |
13 |
120 min |
100 min |
· Size Measurement |
计算工作量 |
1 |
10 min |
10 min |
· Postmortem & Improvement Plan |
事后总结, 并提出改进 |
1 |
10 min |
10 min |
Total |
总计 |
100% |
920min |
700min |
homework-02的更多相关文章
- day 02 ---class - homework
# -*- coding: utf-8 -*-# @Time : 2018/12/20 14:34# @Author : Endless-cloud# @Site : # @File : day 02 ...
- 软件工程 week 02
一.地址链接 1.作业地址:https://edu.cnblogs.com/campus/nenu/2016CS/homework/2110 2.git仓库地址:https://git.coding. ...
- 作业要求20181204-7 Final阶段第1周/共1周 Scrum立会报告+燃尽图 02
作业要求参见https://edu.cnblogs.com/campus/nenu/2018fall/homework/2481 版本控制地址https://git.coding.net/lglr20 ...
- 20181009-3 选题 Scrum立会报告+燃尽图 02
Scrum立会报告+燃尽图(02)选题 此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2191 一.小组介绍 组长:刘莹莹 ...
- Beta阶段第2周/共2周 Scrum立会报告+燃尽图 02
此作业要求参见:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2410] 版本控制地址 https://git.coding.net ...
- 作业要求20181113-4 Beta阶段第1周/共2周 Scrum立会报告+燃尽图 02
作业要求:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2384 版本控制:[https://git.coding.net/lglr201 ...
- Alpha阶段第2周/共2周 Scrum立会报告+燃尽图 02
此次作业要求参见 [https://edu.cnblogs.com/campus/nenu/2018fall/homework/2285] Scrum master:祁玉 一.小组介绍 组长:王一可 ...
- 20181016-4 Alpha阶段第1周/共2周 Scrum立会报告+燃尽图 02
此次作业要求参见 [https://edu.cnblogs.com/campus/nenu/2018fall/homework/2247] Scrum master:祁玉 一.小组介绍 组长:王一可 ...
- c语言1博客作业02
c语言1博客作业02 这个作业属于哪个课程 C语言程序设计 这个作业的要求在哪 [作业要求](https://edu.cnblogs.com/campus/zswxy/SE2019-2/homewor ...
- | C语言I作业02
C语言I博客作业02 标签: 18软件2班 李煦亮 问题 答案 这个作业属于那个课程 C语言程序设计I 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/C ...
随机推荐
- Latex中画出函数文件的调用关系拓扑图
流程图,思维导图,拓扑图通常能把我们遇到的一些复杂的关系结构用图形的方式展现出来.在Latex中要想画这样的拓扑图,有一个很好用的绘图工具包 pgf/tikz . 1.pgf/tikz的安装:pgf/ ...
- MySql 里的IFNULL、NULLIF和ISNULL用法
MySql 里的IFNULL.NULLIF和ISNULL用法 mysql中isnull,ifnull,nullif的用法如下: isnull(expr) 的用法: 如expr 为null,那么isnu ...
- ecshop不同文章分类调用不同文章分类模板
根据需要,不同的文章分类会有不一样的页面风格.也就是说根据文章分类ID来判断,输出不同的文章分类模板. 重点就是文章分类的ID. 打开:article_cat.php $smarty->disp ...
- 有人要分享pjax吗?
安装 1.在 composer.json 的 require里 加入 "yuanchao/pjax-for-laravel-5": "dev-master" 2 ...
- plist文件里边如果最外层是字典的话,读出来是无序的。
如题. 要想使字典有序的话,可以用数组来存放字典,然后读
- nagios检测http
/usr/local/nagios/etc/server/下相应的地址检测加上以下一段 (server下的cfg文件是检测相应服务器的模块) define service{ use ...
- js三级地区联动
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head ...
- ionic + cordova+angularJs 搭建的H5 App完整版总结
为期半个月的项目实践开发,已完整告一段落,团队小组获得第一名,辛苦总算没有白费,想起有一天晚上,整个小组的人,联调到12点才从公司回去,真是心酸.这里总结一下,项目过程中遇到的问题 和感悟.哈哈, ...
- ubuntu selinux
apt install selinux-utils apt install policycoreutils https://zhidao.baidu.com/question/917938889387 ...
- android include进来的组件 调用其子元素
include标签包裹着一个可复用的布局: <include layout="@layout/footer_detail" android:id="@+id/foo ...