Java程序设计实验2 | Java语言基础(一)+https://developer.aliyun.com/article/new?spm=a2c6h.13148508.J_eBhO-wcawiLJRkGqHmozR.89.23164f0egQsi1H#/
3、实验题目:循环结构的应用
1)分别用do-while和for循环计算1+1/2!-1/3!+1/4!-1/5!…的前20项之和。
本题是基础的累加、阶乘的运用。较为基础,故不多作说明。
源代码:
for循环实现
public class S2_3_1 { public static void main(String[] args) { double sum = 0; double fact = 1; for(int i = 1; i <= 20; i++){ fact *= i; //求每项中的阶乘 sum += 1/fact; //将各项累加 } System.out.println(sum); } }
do-while循环实现
public class S2_3_1 { public static void main(String[] args) { double sum = 0; double fact = 1; int i = 1; do { fact *= i++; sum += 1/fact; }while(i <= 20); System.out.println(sum); } }
列出测试数据和实验结果截图:
(2)求1000以内的完全数(一个数等于它的因子之和称为完全数)
通过试除法,找到数n所有的因子并相加,最后作判断即可。
源代码:
public class S2_3_2 { //判断是否是完全数的方法 public static boolean isPerfectNumber(int n){ //一个数等于它的因子之和称为完全数 int sum = 0; //用于记录因子之和 for(int i = 1; i <= n/2; i++){ //试除法寻找因子 if(n%i == 0){ sum += i; //此处i即n的因子 } } //比较因子之和与这个数本身是否相等 if(sum == n){ return true; }else{ return false; } } public static void main(String[] args) { for(int n = 6; n <= 1000; n++){ if(isPerfectNumber(n)){ System.out.println(n); } } } }
(3)微信中的一个拿鸡蛋问题
一筐鸡蛋,1个1个拿,正好拿完。
2个2个拿,还剩1个。
3个3个拿,正好拿完。
4个4个拿,还剩1个。
5个5个拿,还差1个。
6个6个拿,还剩3个。
7个7个拿,正好拿完。
8个8个拿,还剩1个。
9个9个拿,正好拿完。
问:筐里最少有多少鸡蛋?
这个问题非常简单,但必须注意细节:5个5个拿时,是还“差”一个,而不是还“剩”一个。假设有4个鸡蛋,那么此时5个5个拿,就是还差一个的情景。因此,此时的鸡蛋数加上差的1个,恰好是5的倍数。
源代码:
public class S2_3_3 { public static void main(String[] args) { int i = 0; while(true) { i++; if(i%2==1 && i%3==0 && i%4==1 && (i+1)%5==0 && i%6==3 && i%7==0 && i%8==1 && i%9==0){ System.out.println(i); break; } } } }
列出测试数据和实验结果截图:
5、实验题目:课后作业题
(1)求六边形面积,六边形面积可以通过下面公式计算(s是边长)
注:使用Math类中的方法计算tan值。
源代码:
public class Test { public static void main(String[] args) { Scanner reader = new Scanner(System.in); double s = reader.nextDouble(); System.out.println(getArea(s)); } public static double getArea(double s){ double x1 = 6*Math.pow(s,2); double x2 = 4*Math.tan(Math.PI/6); return x1/x2; } }
列出测试数据和实验结果截图:
(2)实现会员注册,要求用户名长度不小于3,密码长度不小于6,若不满足需有提示信息,提示输入有误;注册时两次输入密码必须相同(字符串)
本题的关键是字符串的输入与两个字符串之间的比较方法equals的运用。注意,若要求忽略大小写比较,则用到equalsIgnoreCase()方法。
源代码:
import java.util.Scanner; public class S2_5_2 { public static void main(String[] args) { Scanner reader = new Scanner(System.in); System.out.println("请输入用户名:"); String userName = reader.next(); while(userName.length() < 3) { System.out.println("用户名长度不可小于3!请重新输入:"); userName = reader.next(); } System.out.println("请输入密码:"); String password = reader.next(); while(password.length() < 6) { System.out.println("密码长度不可小于6!请重新输入:"); password = reader.next(); } System.out.println("请确认密码:"); String confirmPassword = reader.next(); if(confirmPassword.equals(password)) { System.out.println("注册成功!"); }else { System.out.println("两次密码不一致!"); } } }
列出测试数据和实验结果截图:
(3)找出两个分教最高的学生:编写程序,提示输入学生的个数、每个学生的名字及其分数,最后显示获得最高分的学生和第二高分的学生
方法一:直接求解
该代码没有用到面向对象的思想,编程思路是分别创建两个数组:分数数组与姓名数组进行分开存储。通过排序代码,以分数为标准对姓名数组进行排序,最后输出前两项的姓名。
源代码:
import java.util.Scanner; public class S2_5_3 { public static void main(String[] args) { Scanner reader=new Scanner(System.in); System.out.println("请输入学生个数"); int num = reader.nextInt(); //创建分数数组和姓名数组进行分开存储 int[] score = new int[num]; String[] name = new String[num]; for(int i=0;i<num;i++) { System.out.println("请输入第"+(i+1)+"个学生的名字"); name[i]= reader.next(); System.out.println("请输入第"+(i+1)+"个学生的成绩"); score[i]=reader.nextInt(); } //直接选择排序 for(int i=0;i<num;i++) { for(int j=i+1;j<num;j++) { if(score[i]<score[j]) { String tmp = name[i]; name[i] = name[j]; name[j] = tmp; } } } System.out.println("第一名为:"+name[0]+"。第二名为:"+name[1]); } }
列出测试数据和实验结果截图:
方法二:面向对象
该方法是上一种方式的优化,核心思路是实现Student类,创建Student数组,并通过直接对Student数组排序的方式最高分的Student对象与第二高分的Student对象。
注意:由于数组排序的过程中设计对象的比较,因此需要重写compareTo()方法才能进行Student数组的排序。
源代码:
import java.util.Arrays; import java.util.Scanner; public class S2_5_3 { public static void main(String[] args) { Scanner reader = new Scanner(System.in); System.out.println("请输入学生的个数:"); int num = reader.nextInt(); Student[] students = new Student[num]; System.out.println("请依次输入学生的姓名与分数:"); for (int i = 0; i < students.length; i++){ System.out.println("学生"+(i+1)); String namei = reader.next(); //① 注意:写成.next()和.nextLine()在此有区别! int scorei = reader.nextInt(); //② students[i] = new Student(namei,scorei); //③ } Arrays.sort(students); //④ System.out.println("获得最高分的学生是:" + students[0]); System.out.println("获得第二高分的学生是:" + students[1]); } } class Student implements Comparable<Student>{ //⑤ String name; int score; public Student(String name, int score) { this.name = name; this.score = score; } //重写compareTo方法以数组排序 @Override public int compareTo(Student o) { return o.score-this.score; } //重写toString方法以打印对象 @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", score=" + score + '}'; } }
代码详解:
- 注释①处写成.next()和.nextLine()在此是有区别的。正确的方式应当是写成reader.next(); 一方面,.next()不会因为获取到上一个输入遗留下来的换行空白符而停止读取;另一方面,在用户实际输入的时候既可以将“姓名”和“分数”用换行隔开,也可以用空格等非换行符隔开。若写成.nextLine()。则会有上面的两个问题,会抛出InputMismatchException
- ③处代码是创建新的Student对象。注意,在创建Student数组的时候,并没有实例化Student对象。数组没有初始化,因此Student数组内均为null。通过构造方法给Student对象的name和score赋值,并实例化数组中的元素。
- ④直接调用Arrays中的方法sort给数组中的元素进行排序。注意:该数组是引用类型,要实现排序必须重写Comparable或Comparator接口,并重写相应的比较方法,也就是指定比较的规则。
- ⑤处实现了Comparable接口。
列出测试数据和实验结果截图:
(4)定义一维数组并初始化,通过键盘任意输入一个数,查找该数是否存在(结果返回下标值)
方法一:数组中查找比对
源代码:
import java.util.Arrays; import java.util.Scanner; public class S2_5_44 { public static void main(String[] args) { Scanner reader=new Scanner(System.in); int[] array={0,1,2,3,4,5,6,7,8,9}; System.out.println("数组为:"); System.out.println(Arrays.toString(array)); System.out.println("请输入一个数:"); int num = reader.nextInt(); int i = 0; for(; i < array.length; i++) { if(num == array[i]) { break; } } if(i < array.length){ System.out.println("该数存在,下标为" + i); }else{ System.out.println("没有找到"); } } }
列出测试数据和实验结果截图:
方法二:将数组转变为字符串后,调用indexOf()方法
注意,将int数组转换为String,不能直接调用Arrays.toString()方法。因为该方法输出的内容并不完全是原数组中的,而是还有分隔符逗号、前后中括号[] 等。通过调试可以看到:
我们希望0下标的位置是"0",但这里却是"["。Java中没有库函数可以实现int数组直接转换成String的方法,因此我们需要自己实现一个myToString()来完成,逻辑也并不难。
源代码:
import java.util.Arrays; import java.util.Scanner; public class S2_5_4 { public static void main(String[] args) { Scanner reader = new Scanner(System.in); int[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; System.out.println("数组为:"); System.out.println(Arrays.toString(array)); System.out.println("请输入一个数:"); int num = reader.nextInt(); //将待查找的数转变成String类型,再查找 String strNum = String.valueOf(num); //调用自己实现的方法,将int数组转变成String数组 String strArray = myToString(array); //获取查找下标值 int ret = strArray.indexOf(strNum); if(ret != -1){ System.out.println("找到了,下标是:" + ret); } else { System.out.println("没有找到"); } } //自己实现将int数组转换为String的方法 public static String myToString(int[] array) { String str = ""; for (int x : array) { str += x+""; } return str; } }
列出测试数据和实验结果截图:
方法三:调用Arrays工具类中的binarySearch()方法
如图,这是binarySearch()一个方法的api文档。通过文档可知,配合sort()方法,可以直接调用二分查找方法实现查找。
源代码:
import java.util.Arrays; import java.util.Scanner; public class S2_5_4 { public static void main(String[] args) { Scanner reader = new Scanner(System.in); int[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; System.out.println("数组为:"); System.out.println(Arrays.toString(array)); System.out.println("请输入一个数:"); int num = reader.nextInt(); Arrays.sort(array); //必须先进行排序 int ret = Arrays.binarySearch(array,num); //调用二分查找方法 if(ret < 0) { System.out.println("没有找到!"); }else{ System.out.println("找到了,下标为" + ret); } } }
(5)编写一个程序,将二维数组a转置后存入数组b(所谓转置就是行列互换)
例如:
源代码:
import java.util.Arrays; import java.util.Scanner; public class S2_5_5 { public static void main(String[] args) { Scanner reader = new Scanner(System.in); System.out.println("请输入数组的行数n与列数m:"); int n = reader.nextInt(); int m = reader.nextInt(); int[][] src = new int[n][m]; int[][] dst = new int[m][n]; System.out.printf("请输入一个%d*%d的数组:\n",n,m); for(int i = 0; i < src.length;i++) { for(int j = 0; j < src[i].length; j++) { src[i][j] = reader.nextInt(); } } for(int i = 0; i < dst.length; i++) { for(int j = 0; j < dst[i].length; j++) { dst[i][j] = src[j][i]; } } System.out.println("转制后的二位数组为:"); //System.out.println(Arrays.deepToString(dst)); for(int i = 0; i < dst.length; i++) { for(int j = 0; j < dst[i].length; j++) { System.out.print(dst[i][j] + " "); } System.out.println(); } } }
列出测试数据和实验结果截图:
三、实验总结
- 完成上述实验,我更熟地掌握了Java的基础语法,包括:
1. Java关于标识符的命名规则,Java标识符可以字母、数字、下划线和美元符构成,且数字不能开头。类名用大驼峰,变量名、方法名用小驼峰。
2. 掌握了8种基本数据类型int,byte,short,char,long,float,double,Boolean的使用情况和相应的类型转换方法。
3. 我熟悉了各种运算符包括自增、自减、三目运算符等的优先级和结合方向。
4. 我掌握了控制结构的3种语句,包括if、switch选择语句、while、do-while、for、for-each循环语句。
5. 我掌握了Java输入数据的基本方法:Scanner。我可以熟练地通过调用Scanner对象输入各种数据类型的数据进行编程。
6. 我掌握了方法的定义和调用格式,能正确写出Java定义方法的语法。也理解了方法调用和参数传递的原理,包括值传递和址传递。
7. 我掌握了方法的重载,重载的条件是方法的名称必须相同,参数列表必须不同,返回值类型不做要求。
8. 我也理解了方法的递归调用,递归就是方法自己调用自己,会在虚拟机栈中建立栈帧。
9. 在与数组相关的实验中,我掌握了数组的定义、动态和静态初始化格式。我能通过for循环对一维数组和二维数组进行遍历,能完成数组的转置、数组的排序,构建引用类型的数组。也可以熟练通过Array工具类,直接调用Arrays中的方法进行数组排序和逆序。
- 在编程中我没有遇到难以解决的问题。遇到唯一的问题是在求完数时,本来需要对一个数进行试除,然后计算该数的所有因子之和。我在for循环判断试除因子范围时,将i的界限写成了i <=Math.sqrt(n),但输出结果有误(什么也没输出)。通过调试,后来我将i 改为 i <= n/2,就能正确输出结果了。这是因为我一开始没有意识到因子有对称性这个特点。
- 最后,通过实验,我对基础算法进行了很好的复习。