这个作业要求在哪里 | https://edu.cnblogs.com/campus/jssf/infor_computation17-31/homework/10454 |
---|---|
我在这个课程的目标是 | 学会软件开发的功能,会修改简单的代码,可根据现有代码实现改编满足需求 |
此作业在哪个具体方面帮我实现目标 | 学会建立单元测试,测试程序 |
其他参考文献 | https://blog.csdn.net/zavens/article/details/3876531 https://netbeans.org/kb/docs/java/junit-intro_zh_CN.html |
作业正文 | https://i-beta.cnblogs.com/posts/edit;postId=12431633 |
实现数组中最大子数组的和。
作业要求
1.用类/函数来实现
2.需求:希望返回 3 种信息:(1)最大子数组的和(2)最大子数组开始的下标 (3)最大子数组结束的下标
3.从文本文件中读输入的数据,熟悉文件操作,文件有两种数据:(1)第一个数字:这次测试中有多少个数据,数字后面是冒号;(2)后续数字:每个数据的值,用逗号隔开。
数组程序方法
(1)暴力求解,运行时间是n².暴力求解也是容易理解的做法,简单来说,我们只要用两层循环枚举起点和终点,这样就尝试了所有的子序列,然后计算每个子序列的和,然后找到其中最大的即可
(2)分治策略,运行时间是nlogn.
使用分治技术意味着我们要将子数组划分为两个规模尽量相等的子数组,也就是找到子数组的中央位置(比如mid),然后考虑求解两个子数组A[low..mid]和A[mid+1..high]。A[low..high]的任意连续子数组A[i..j]所处的位置必然是以下三种情况之一:
(a)完全位于子数组A[low..mid]中,因此low≤i≤j≤mid
(b)完全位于子数组A[mid+1..high]中,因此mid≤i≤j≤high
(c)跨越了中点,因此low≤i≤mid≤j≤high
(3)贪心算法,运行时间是n
将子串和为负数的子串丢掉,只留和为正的子串。
实现代码(C++)
//典型分治思想,适合使用递归处理。我们可以考虑将给定的数组分成两部分,
//那么最大子数组必定存在于左侧部分,或者右侧部分,或者是跨越了分界线的部分。
//那么,只要分别求出这三种情况下的最大子数组,再进行比较,就能得出最后的结果。
#include<iostream>
#include<cstdlib>
using namespace std;
void find_max_crossing_subarray(int* arr, int low, int mid, int high, int& cross_low, int& cross_high, int& cross_sum)
{
int sum = 0;
int left_sum = arr[mid] - 1;
for (int i = mid; i >= low; i--)
{
sum += arr[i];
if (sum >= left_sum)
{
left_sum = sum;
cross_low = i;
}
}
sum = 0;
int right_sum = arr[mid + 1] - 1;
for (int i = mid + 1; i <= high; i++)
{
sum += arr[i];
if (sum >= right_sum)
{
right_sum = sum;
cross_high = i;
}
}
cross_sum = left_sum + right_sum;
}
void find_max_subarray(int* arr, int low, int high, int& result_low, int& result_high, int& result_sum)
{
if (low == high)
{
result_low = low;
result_high = high;
result_sum = arr[low];
return;
}
int mid = (low + high) / 2;
int left_low = 0;
int left_high = 0;
int left_sum = 0;
find_max_subarray(arr, low, mid, left_low, left_high, left_sum);
int right_low = 0;
int right_high = 0;
int right_sum = 0;
find_max_subarray(arr, mid + 1, high, right_low, right_high, right_sum);
int cross_low = 0;
int cross_high = 0;
int cross_sum = 0;
find_max_crossing_subarray(arr, low, mid, high, cross_low, cross_high, cross_sum);
if (left_sum >= right_sum && left_sum >= cross_sum)
{
result_low = left_low;
result_high = left_high;
result_sum = left_sum;
}
else if (right_sum >= left_sum && right_sum >= cross_sum)
{
result_low = right_low;
result_high = right_high;
result_sum = right_sum;
}
else
{
result_low = cross_low;
result_high = cross_high;
result_sum = cross_sum;
}
}
int main()
{
int A[] = {-32,-10,33,-23,32,-12,41,-12,1,3,5,-98,70,-21,10,-9,61};
cout<<"17:";
for(int i=0;i<=16;i++){
cout<<A[i]<<",";
}
cout<<endl;
int low = 0;
int high = 0;
int sum = 0;
find_max_subarray(A, 0, 16, low, high, sum);
cout<<"则最大子数组为:"<< "{";
for (int i = low; i <= high; i++)
{
cout << A[i] << ", ";
}
cout << "(sum = " << sum << ")" << "}" << endl;
cout<<"输出左下标、右下标及最大值:"<<"["<<low<<","<<high<<","<<sum<<"]"<<endl;
system("pause");
return 0;
}
测试包括测试文件读入与计算(测试过程通过程序新建一个文件,内容可以为上述数字,测试完后得删除文件)
单元测试
用C++单元测试:
用Java单元测试:
用NetBeans Java进行单元测试要用junit来进行。
单元测试代码
#include "stdafx.h"
using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
namespace TestProject1
{
[TestClass]
public ref class UnitTest1
{
private:
TestContext^ testContextInstance;
public:
/// <summary>
///获取或设置测试上下文,该上下文提供
///有关当前测试运行及其功能的信息。
///</summary>
property Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ TestContext
{
Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ get()
{
return testContextInstance;
}
System::Void set(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ value)
{
testContextInstance = value;
}
};
#pragma region Additional test attributes
//
//编写测试时,可以使用以下附加特性:
//
//在运行类中的第一个测试之前,使用 ClassInitialize 来运行代码
//[ClassInitialize()]
//static void MyClassInitialize(TestContext^ testContext) {};
//
//在类中的所有测试都已运行之后,使用 ClassCleanup 来运行代码
//[ClassCleanup()]
//static void MyClassCleanup() {};
//
//在运行每个测试之前,使用 TestInitialize 来运行代码
//[TestInitialize()]
//void MyTestInitialize() {};
//
//在每个测试运行完之后,使用 TestCleanup 来运行代码
//[TestCleanup()]
//void MyTestCleanup() {};
//
#pragma endregion
[TestMethod]
void TestMethod1()
{
//
// TODO: 在此处添加测试逻辑
//
Assert::AreEqual(111,sum);
Assert::AreEqual(12,low);
Assert::AreEqual(16,high);
};
};
}
代码push到仓库
码云链接:https://gitee.com/yu66688/firstwarehouse/blob/master/shuzu.cpp
个人成长
(1)大学学习回顾:大一开始接触简单地计算机应用软件(MS Office)及基本的C++语言编程,学习了编程基础知识,代码编程则只会简单算法。大二学习了Java语言,会做一些简单的图形界面,会用java语言、C++语言的编程;还进一步学习了数据结构课程,了解了计算机数据的基本知识。大三学习了数据库,操作系统,ASP,MATLAB科学计算等课程具体了解了计算机代码、网站编写的操作。
(2)个人期望:希望在这学期的计算与软件工程课程的学习中能通过自行学习和老师的帮助完成简单地软件开发。能提高代码编程能力。
预习
代码规范和复审
1.“代码规范”可以分成两个部分。
(1)代码风格规范。主要是文字上的规定,看似表面文章,实际上非常重要。
(2)代码设计规范。牵涉到程序设计、模块之间的关系、设计模式等方方面面,这里有不少与具体程序设计语言息息相关的内容(如C/C++/Java/C#),但是也有通用的原则,这里主要讨论通用的原则。
2.在代码复审后,开发者应该把复审过程中的记录整理出来:
(1)更正明显的错误。
(2)对于无法很快更正的错误,要在TFS中创建Bug把它们记录下来。
(3)把所有的错误记在自己的一个“我常犯的错误”表中,作为以后自我复审的第一步。
结对编程
在结对编程中,因为有随时的复审和交流这样,程序中的错误就会少得多,程序的初始质量会高很多,这样会省下很多以后修改、测试的时间。结对编程有如下的好处:
(1)在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。
(2)对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感。
(3)在心理上, 当有另一个人在你身边和你紧密配合, 做同样一件事情的时候, 你不好意思开小差, 也不好意思糊弄。
(4)在企业管理层次上,结对能更有效地交流,相互学习和传递经验,能更好地处理人员流动。因为一个人的知识已经被其他人共享。
运用得当,结对编程能得到更高的投入产出比。
方法:断言、桥梁、说服、吸引
反馈
最外层: 行为和后果
中间层: 习惯和动机
最内层: 本质和基本属性