以下为个人学习笔记和习题整理
课程:零基础学 Java 语言 - 浙江大学 - 翁恺 @ 中国大学 MOOC
https://www.icourse163.org/course/ZJU-1001541001
# 课堂笔记
# 数组
- 数组是一种容器(放东西的东西)
- 数组中的每个数据叫做元素。
# 数组变量
# 定义与初始化
| <类型>[]<名字> = new <类型>[元素个数]; |
| |
| int[] numbers = new int[10]; |
| double[] averages = new double[20]; |
- 元素个数必须给出
- 元素个数必须是整数
- 元素个数可以是变量 :先让用户输入数组的个数,然后将这个数确定为数组的元素个数
| int[] scores = {87,98,69,54,65,76,87,99}; |
- 数组大小不需要给出
- 可以用
length
获得数组大小
# 数组元素
数组的索引或下标都是从 0 开始的
源自于 C 语言,其编译器从 0 开始更易于计算
最小的下标是 0
,最大的下标是 元素个数-1
编译器不会检查下标是否有效。
如果运行时出现了无效下标,会导致程序终止。
# 赋值
| int[] a = new int[10]; |
| a[0] = 5; |
| int[] b = a; |
| b[0] = 16; |
| |
| System.out.println(a[0]); |
| int[] a1 = {1,2,3,4,5}; |
| int[] a2 = a1; |
| for ( int i=0; i<a2.length; ++i ) { |
| a2[i] ++; |
| } |
| for ( int i=0; i<a1.length; ++i ) { |
| System.out.println(a1[i]); |
| } |
示意图:
Error: Failed to launch the browser process! spawn /Applications/Google Chrome.app/Contents/MacOS/Google Chrome ENOENT
TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
数组变量 ≠ 数组
数组变量
是 数组
的管理者,而不是所有者,非 数组
本身数组
必须创建出来,然后交给 数组变量
管理数组变量
之间的赋值,是管理权限的赋予数组变量
之间的比较,是判断是否管理同一个 数组
- 两个
数组
即使内容相同也不等同,判断两个 数组
是否相等,需遍历逐个元素 - 复制
数组
,必须遍历源数组,将每个元素逐一拷贝给目的数组
# 遍历
# for 循环
让循环变量 i 从 0 到小于数组的 length,这样循环体内最大的 i 正好是数组最大的有效下标。
| |
| int[] data = {2,3,4,5,6,7,8,9,10}; |
| int x = in.nextlnt(); |
| int loc = -1; |
| for( int i=0; i < data.length; i++ ) { |
| if(x == data[i]) { |
| loc = i; |
| break; |
| } |
| } |
| if( loc > -1 ) { |
| System.out.println(x+"是第"+(loc+1)+"个"); |
| } else { |
| System.out.println(x+"不在其中"); |
| } |
- 常见错误:
- 循环结束条件写成 <= 数组长度
- 离开循环后,继续使用 i 的值来做数组元素的下标
# for-each 循环
- 数组中的每一个元素取出来作为这个类型的变量
- 非常适用于遍历读出数组,但是不能修改数组,因为只能读出数组中的某一元素,但不知道索引值。
| |
| int[] data = {2,3,4,5,6,7,8,9,10}; |
| int x = in.nextlnt(); |
| boolean found = false; |
| for(int k : data) { |
| |
| |
| if(x == k) { |
| found = true; |
| break; |
| } |
| } |
| if( found ) { |
| System.out.println(x+"在其中"); |
| } else { |
| System.out.println(x+"不在其中"); |
| } |
# 例子
# 判断是否为素数
- 方案一:从
2
到 x-1
测试是否可以整除 循环x次
| int x = in.nextInt(); |
| boolean isPrime = true; |
| |
| if ( x == 1 ) { |
| isPrime = false; |
| } |
| for ( int i=2; i<x; i++ ) { |
| if ( x % i == 0 ) { |
| isPrime = false; |
| break; |
| } |
| } |
| |
| if ( isPrime ) { |
| System.out.println(x+"是素数"); |
| } else { |
| System.out.println(x+"不是素数"); |
| } |
- 方案 2: 去掉偶数后,从
3
到 x-1
,每次加 2
循环次数减半x/2
| int x = in.nextInt(); |
| boolean isPrime = true; |
| |
| if ( x == 1 || x%2 == 0 && x!= 2 ) { |
| isPrime = false; |
| } else { |
| for ( int i=3; i<x; i+=2 ) { |
| if ( x % i == 0 ) { |
| isPrime = false; |
| break; |
| } |
| } |
| } |
| |
| if ( isPrime ) { |
| System.out.println(x+"是素数"); |
| } else { |
| System.out.println(x+"不是素数"); |
| } |
- 方案 3:无须到
x-1
,到 sqrt(x)
就够了 遍历次数最少,x的平方根
| int x = in.nextInt(); |
| boolean isPrime = true; |
| |
| if ( x == 1 || x%2 == 0 && x!= 2 ) { |
| isPrime = false; |
| } else { |
| for ( int i=3; i < Math.sqrt(x); i+=2 ) { |
| if ( x % i == 0 ) { |
| isPrime = false; |
| break; |
| } |
| } |
| } |
| |
| if ( isPrime ) { |
| System.out.println(x+"是素数"); |
| } else { |
| System.out.println(x+"不是素数"); |
| } |
# 构造素数表
| Scanner in = new Scanner(System.in); |
| int[] primes = new int[50]; |
| primes[0]= 2; |
| int cnt = 1; |
| |
| MAIN_LOOP: |
| for(int x = 3; cnt<50; x++) { |
| for(int i= 0; i<cnt; i++) { |
| if( x%primes[i] == 0) { |
| continue MAIN_LOOP; |
| } |
| } |
| primes[cnt++] = x; |
| |
| } |
| |
| for(int k:primes) { |
| System.out.print(k+" "); |
| } |
| Scanner in = new Scanner(System.in); |
| boolean[] isPrime = new boolean[100]; |
| |
| for(int i = 0; i < isPrime.length; i++) { |
| isPrime[i] = true; |
| } |
| for(int i = 2; i < isPrime.length; i++) { |
| if(isPrime[i]) { |
| for(int k = 2; i * k < isPrime.length; k++) { |
| |
| isPrime[i*k]= false; |
| } |
| } |
| } |
| |
| for(int i= 2;i<isPrime.length;i++) { |
| if(isPrime[i]) { |
| System.out.print(i+" "); |
| } |
| } |
# 二维数组
| int[][] a = new int[3][5]; |
可以理解为 a 是一个 3 行 5 列 的矩阵:
a[0][0] | a[0][1] | a[0][2] | a[0][3] | a[0][4] |
a[1][0] | a[1][1] | a[1][2] | a[1][3] | a[1][4] |
a[2][0] | a[2][1] | a[2][2] | a[2][3] | a[2][4] |
# 遍历
| for(i=0;i<3;i++) { |
| for(j=0;j<5;j++) { |
| a[i][j]=i*j; |
| } |
| } |
a[i][j]
是一个 int- 表示第
i
行第 j
列上的单元
# 初始化
| int[][] a = { |
| {1,2,3,4}, |
| {1,2,3}, |
| }; |
- 编译器来数数
- 每行一个 {},逗号分隔
- 最后的逗号可以存在,来自 C 语言的古老传统
- 如果省略,表示补零
# 例子
# tic-tac-toe 游戏
| final int SIZE = 3; |
| int[][] board = new int[SIZE][SIZE]; |
| boolean gotResult = false; |
| int numOfX = 0; |
| int numOfO = 0; |
| |
| for ( int i=0; i<SIZE; i++ ) { |
| for ( int j=0; j<SIZE; j++ ) { |
| board[i][j] = in.nextInt(); |
| } |
| } |
| for ( int i=0; i<SIZE; i++ ) { |
| numOfX = 0; |
| numOfO = 0; |
| for ( int j=0; i<SIZE; i++ ) { |
| if ( board[i][j] == 1 ) { |
| numOfX ++; |
| } else { |
| numOfO ++; |
| } |
| } |
| if ( numOfX == SIZE || numOfO == SIZE ) { |
| gotResult = true; |
| break; |
| } |
| } |
| if ( !gotResult ) { |
| for ( int i=0; i<SIZE; i++ ) { |
| numOfX = 0; |
| numOfO = 0; |
| for ( int j=0; i<SIZE; i++ ) { |
| if ( board[j][i] == 1 ) { |
| numOfX ++; |
| } else { |
| numOfO ++; |
| } |
| } |
| if ( numOfX == SIZE || numOfO == SIZE ) { |
| gotResult = true; |
| break; |
| } |
| } |
| } |
| if ( !gotResult ) { |
| numOfX = 0; |
| numOfO = 0; |
| for ( int i=0; i<SIZE; i++ ) { |
| if ( board[i][i] == 1 ) { |
| numOfX ++; |
| } else { |
| numOfO ++; |
| } |
| } |
| if ( numOfX == SIZE || numOfO == SIZE ) { |
| gotResult = true; |
| } |
| } |
| if ( !gotResult ) { |
| numOfX = 0; |
| numOfO = 0; |
| for ( int i=0; i<SIZE; i++ ) { |
| if ( board[i][SIZE-i-1] == 1 ) { |
| numOfX ++; |
| } else { |
| numOfO ++; |
| } |
| } |
| if ( numOfX == SIZE || numOfO == SIZE ) { |
| gotResult = true; |
| } |
| } |
| if ( gotResult ) { |
| if ( numOfX == SIZE ) { |
| System.out.println("X WIN"); |
| } else { |
| System.out.println("O WIN"); |
| } |
| } |
# 小测验
若有定义: int a[2][3];
,则以下选项中不越界的正确的访问有:
- a[2][0]
- a[2][3]
- a[0][0]
- a[0][3]
以下程序片段的输出结果是:
| int[][] m = { {1,4,7},{2,5,8},{3,6,9}, }; |
| int i,j,k=2; |
| for ( i=0; i<3; i++ ) { |
| System.out.print(m[k][i]); |
| } |
# 编程题
# 题目 1. 多项式加法(5 分)
题目内容
一个多项式可以表达为 x 的各次幂与系数乘积的和,比如:
2x6+3x5+12x3+6x+20
现在,你的程序要读入两个多项式,然后输出这两个多项式的和,也就是把对应的幂上的系数相加然后输出。
程序要处理的幂最大为 100。
输入格式
总共要输入两个多项式,每个多项式的输入格式如下:
每行输入两个数字,第一个表示幂次,第二个表示该幂次的系数,所有的系数都是整数。第一行一定是最高幂,最后一行一定是 0 次幂。
注意第一行和最后一行之间不一定按照幂次降低顺序排列;如果某个幂次的系数为 0,就不出现在输入数据中了;0 次幂的系数为 0 时还是会出现在输入数据中。
输出格式
从最高幂开始依次降到 0 幂,如:
2x6+3x5+12x3-6x+20
注意其中的 x 是小写字母 x,而且所有的符号之间都没有空格,如果某个幂的系数为 0 则不需要有那项。
输入样例
6 2
5 3
3 12
1 6
0 20
6 2
5 3
2 12
1 6
0 20
输出样例
4x6+6x5+12x3+12x2+12x+40
# 解题代码
| import java.util.Scanner; |
| |
| public class Main { |
| |
| public static void main(String[] args) { |
| Scanner in = new Scanner(System.in); |
| |
| int[] poly = new int[101]; |
| int a, b; |
| boolean isFirst = true; |
| |
| for (int i = 0; i < 2; i++) { |
| do { |
| a = in.nextInt(); |
| b = in.nextInt(); |
| |
| poly[a] += b; |
| |
| } while( a != 0 ); |
| } |
| |
| for (int j = 100; j >= 0; j--) { |
| if( poly[j] != 0 ) { |
| |
| if (!isFirst && poly[j] > 0) { |
| System.out.print("+"); |
| } |
| |
| if (poly[j] != 1) { |
| if(poly[j] == -1) { |
| System.out.print("-"); |
| } else { |
| System.out.print(poly[j]); |
| } |
| } |
| |
| |
| if (j > 0) { |
| System.out.print("x"); |
| if (j > 1) { |
| System.out.print(j); |
| } |
| } |
| |
| isFirst = false; |
| |
| } |
| } |
| |
| } |
| } |