中南大学计算机学院实验报告
课程名称 Java面向对象程序设计SSD3
实验项目名称 实验2《一维数组》
学生姓名 Xi_Chen123 专业班级 ********* 学号 **********
实验成绩 日期 2022-4-28
实验学时: 2
每组人数: 1
实验类型: 1 (1:基础性 2:综合性 3:设计性 4:研究性)
实验要求: 1 (1:必修 2:选修 3:其它)
实验类别: 2 (1:基础 2:专业基础 3:专业 4:其它)
一、实验目的
学习一维数组的用法、方法的定义和调用。
二、实验内容
1. (P236, 7.3)编写程序,读取1-100之间的整数,然后计算每个数出现的次数。假定输入是以0结束的。以下是程序运行示例:
| 输入1-100之间的整数:2 5 5 4 3 23 2 0 [回车] 2 出现 2 次 3 出现 1 次 4 出现 1 次 5 出现 2 次 23 出现 1 次 |
2. (P237,7.10)编写一个方法,求出数组中最小元素的下标。如果这样的元素个数大于1,则返回最小下标。使用下面的方法头:
public static int indexofSmallestElement(double[] array)
编写测试程序,提示用户输入10个数字,调用这个方法,返回最小元素的下标,然后显示这个下标值。
3. (P236,7.5)编写程序, 读入10个数并显示互不相同的数(即一个数出现多次,但仅显示一次)。提示,读入一个数,如果它是一个新数,则将它存储在数组中,如果该数已经在数组中,则忽略它。输入之后,数组包含的都是不同的数。以下是运行示例:
输入10个整数:1 2 3 2 1 6 3 4 5 2
互不相同的数为:1 2 3 6 4 5
4.(P240,7.27)如果两个数组list1和list2内容相同,那么就说它们是相同的。使用下面的方法头编写一个方法,如果list1和list2是相同的,该方法就返回true:
public static boolean equal(int[ ] list1, int[ ] list2)
编写一个测试程序,提示用户输入两个整数数列,然后显示它们两个是否相同。以下是运行示例。注意输入的第一个数字表示数列中元素的个数。
提示:可考虑使用230-231页Arrays类提供的方法进行组合调用
| 输入list1: 5 2 5 6 6 1 输入list2: 5 5 2 6 1 6 这两个数列是相同的 |
| 输入list1: 5 5 5 6 6 1 输入list2: 5 2 5 6 1 6 这两个数列是不同的 |
5. (附加题6.31 信用卡号的合法性,可选做)信用卡号遵循下面的模式。一个信用卡号必须是13-16位的整数。它的开头必须是:
4,指visa卡
5,指master卡
37,指American Express卡
6,指Discovery卡
在1954年,IBM的Hans Luhn提出一种算法,该算法可以验证信用卡号的有效性。这个算法在确定输入的卡号是否正确,或者这张信用卡是否能被正确扫描是非常有用的。该方法通常被称为Luhn检测或Mod10 检测,描述如下(假设卡号是4388576018402626)
- 从右至左对偶数位上的数字翻倍。如果数字翻倍后是一个两位数,那么就将这两位加在一起得到一位数。
2*2 =4
2*2=4
4*2=8
1*2=2
6*2=12(1+2=3)
5*2=10(1+0=1)
8*2=16(1+6=7)
4*2=8
- 将第一步得到的所有一位数相加。
4+4+8+2+3+1+7+8=37
- 将卡号里从右往左奇数位上所有数字相加。
6+6+0+8+0+7+8+3=38
- 将第二步和第三步得到的结果相加。
37+38=75
- 如果第四步得到的结果能被10整除,则卡号是合法的,否则是不合法的。
75%10 !=0
编写程序,提示用户输入一个long型整数的信用卡号码,显示这个数字是合法还是非法的。使用下面的方法设计程序:
public static int sumOfDoubleEvenPlace(long number)
public static int getDigit(int number)
public static int sumOfOddPlace(long number)
public static boolean prefixMatched(long number, int d)
public static int getSize(long d)
public static long getPrefix(long number, int k)
三、实验要求:
要求每个学生独立完成实验任务。
四、实验报告
1.在一周内完成本项目实验,提交实验文档,包括:.java文件(分别对应以上各题,不需要.class文件)打包成一个名为“实验2”的.rar或.zip文件,以及实验报告1份(格式与要求见下),报告命名为“班级名(如“2101”)_学号_姓名_实验2.doc”。
2. 实验结果与分析
实验一
实验二
实验三
实验四
实验五(附加题)
3. 心得体会
(记录实验感受、上机过程中遇到的困难及解决办法、遗留的问题、意见和建议等。)
本次实验的主题为《一维数组》,由于在与C++中的部分知识点和逻辑形式是相同的,所以学习起来较为简单,完成本次实验的过程较为顺利,主要的是Java中自带的API的不熟悉,除此以外,并无太多意外的出现。
在进行实验一的过程中,原本的计划是通过一个数组来存储输入的数字,再用另外一个数组存储出现的次数,两个数组结合最终得到最后结果的输出。后来在实现的过程中遇到了很多问题,譬如循环终止条件、随着数据量的增大程序越来越复杂等问题。后来在与同学交流的过程中,意外想到了一个新的思路。先创建一个能存储101个数据的整型数组,对于每一个数据来说,其对应的下标存储表示在这个元素内部存储的整数,整型数组内部存储该整数出现的次数。例如:num[10]=5;表示10在输入中的出现次数为5。
在进行实验二的过程中,其实并不需要对整个数组进行排序,只需要对整个数组进行一次遍历,用一个double类型的数据min保存遍历中所遇到的最小数据,如果在遍历中遇到更小的则替换min中保存的数据即可,最后返回min得到result。
在进行实验三的过程中,曾想过在输入这个数的过程中就对数据进行处理和保存,后来发现在输入阶段的for循环中程序太过冗杂,可读性较差,于是先将所有数据保存在一个num数组中,后对num数组进行遍历找到互不相同的数后存入answer数组中,最后输出answer数组即可,程序简洁了许多,可读性增强。其中比较容易忽略的一点是第一个数可以直接存储进answer中,以减少运算,因为此时没有数据和它相同。
在进行实验四的过程中,程序题目中规中矩,并没有什么太过困难的地方。在查阅书籍的过程中了解到了很多关于Arrays的实用API,并一一做了实践来加强印象(sort和parallelSort:排序;binarySearch:二分查找法,返回对应元素的下标;fill:填充;toString:返回array中存储的数据的字符串)。在本题中我们使用了sort方法来对数组整体进行一个排序,其目的是为了在后面的对比中更方便比较元素相同但元素顺序不同的两个数列。
实验五比较苦难,首先是阅读量比较大,且我们在日常生活中也很少关注到信用卡号的合法规则,对于我们提取信息的能力要求较高;其次判断卡号是否合法的过程也比较繁琐,在程序设计的过程中难免会考虑不周产生bug;最后是模块化代码的编写,如果对模块化代码的编写思路不太清晰的情况下就开始编写函数,会造成进度推进缓慢、函数多余、思路冗杂、可读性差等各种问题,可以说是本次实验中的压轴题型。
模块化思想(简易流程图,并非正规格式)
在编写实验五的过程中还有一个小问题值得思考:在对long类型的数据进行强转成int类型的过程中,需要将后面的整体也加上括号,否则会导致在运算的过程中使数据出现错误
debug一次后
需要将while中的
result=result+(int)number%10;
改为
result=result+(int)(number%10);
这个问题非常小,但是很难注意到,因为这样写是符合语法规则的,程序编译器不会报错,程序会正常运行,但是我们得到的结果却是错误的。当我的程序无法得出正确的结论时,纠正起来就非常麻烦。这又一次体现出了模块化的好处:修改bug逻辑清晰。
首先将mian函数运行一遍,观察是哪一个模块出现了错误,然后跳转到出现错误的模块再次进行调试。这道实验题中有许多for循环,如果把所有的程序都整合到main函数中那么每debug一次就需要把所有的for循环重新运行一次,浪费时间降低效率。故而在以后的编程过程中需要继续打磨自己模块化编程的能力
4.【附源程序】(除了单独的.java文件,也请复制到实验文档里,方便批阅者评阅)
实验1
package com.xc2;
import java.util.Scanner;
public class exercise1 {
public static void main(String[] args) {
System.out.print("输入1-100之间的整数:");
//输入并存储数据
Scanner sc=new Scanner(System.in);
int[] count=new int[101];
while(true){
String s=sc.next();
int num=Integer.parseInt(s);
if(num==0){
break;
}else {
count[num]++;
}
}
//输出结果
for(int i=1;i<101;i++){
if(count[i]!=0){
System.out.println(i+"出现"+count[i]+"次");
}
}
}
}
实验2
package com.xc2;
import java.util.Scanner;
public class exercise2 {
public static void main(String[] args) {
System.out.println("Please input ten numbers:");
//输入并保存数字
double[] num=new double[10];
Scanner sc=new Scanner(System.in);
for(int i=0;i<10;i++){
num[i]=sc.nextInt();
}
//找到最小元素
int result=indexOfSmallestElement(num);
//输出下标
System.out.println(result);
}
public static int indexOfSmallestElement(double[] array){
double min=array[0];
int result=0;
for(int i=1;i< array.length;i++){
if(min>array[i]){
min=array[i];
result=i;
}
}
return result;
}
}
实验3
package com.xc2;
import java.util.Scanner;
public class exercise3 {
public static void main(String[] args) {
//录入数据
Scanner sc=new Scanner(System.in);
System.out.print("输入10个整数:");
int[] num=new int[10];
for(int i=0;i<10;i++){
num[i]=Integer.parseInt(sc.next());
}
//判断是否与前面的数重复
int[] answer=new int[10];
answer[0]=num[0];//第一个数直接存储
int count=1;
for(int i=1;i<10;i++){
boolean flag=true;
for(int j=0;j
实验4
package com.xc2;
import java.util.Arrays;
import java.util.Scanner;
public class exercise4 {
public static void main(String[] args) {
//输入数据
Scanner sc=new Scanner(System.in);
System.out.print("输入list1:");
int size1=Integer.parseInt(sc.next());
int[] list1=new int[size1];
for(int i=0;i
实验5(附加题)
package com.xc2;
import java.util.Scanner;
public class exercise5 {
public static void main(String[] args) {
//输入卡号
System.out.println("Please input the number of your card:");
Scanner sc=new Scanner(System.in);
long id=sc.nextLong();
//检测是否符合
boolean judge=isValid(id);
//输出结果
if(judge){
System.out.println("The card is valid.");
}else {
System.out.println("The card isn't valid.");
}
}
//判断是否符合条件
public static boolean isValid(long number){
//判断长度
int size=getSize(number);
if(size>16|size<13) return false;
//判断前缀
boolean judge=prefixMatched(number,4)|prefixMatched(number,5)|prefixMatched(number,37)|prefixMatched(number,6);
if(!judge) return false;
//Luhn检测
return (sumOfOddPlace(number) + sumOfDoubleEvenPlace(number)) % 10 == 0;
}
//第二步结果,偶数项乘二转化相加
public static int sumOfDoubleEvenPlace(long number){
number=number/10;
int result=0;
while (number!=0){
int temp=(int)(number%10*2);
result=result+getDigit(temp);
number=number/100;
}
return result;
}
//两位数转化
public static int getDigit(int number){
if(number<10){
return number;
}else {
return number%10+number/10%10;
}
}
//奇数项求和
public static int sumOfOddPlace(long number){
int result=0;
while (number!=0){
result=result+(int)(number%10);
number=number/100;
}
return result;
}
//前缀匹配
public static boolean prefixMatched(long number, int d){
//获取长度
int size=getSize(d);
//对比前几位与d
return getPrefix(number, size) == d;
}
//求长度
public static int getSize(long d){
int count=0;
while (d!=0){
d=d/10;
count++;
}
return count;
}
//得到前k位
public static long getPrefix(long number, int k){
int size=getSize(number);
for(int i=0;i



