以下为个人学习笔记和习题整理
课程:零基础学 Java 语言 - 浙江大学 - 翁恺 @ 中国大学 MOOC
https://www.icourse163.org/course/ZJU-1001541001

# 课堂笔记

# 数组

  • 数组是一种容器(放东西的东西)
    • 一旦创建,不能再改变大小。
  • 数组中的每个数据叫做元素。
    • 所有元素具有相同的数据类型。

# 数组变量

# 定义与初始化

  • new 创建数组,各元素会得到默认的 0
<类型>[]<名字> = new <类型>[元素个数];
int[] numbers = new int[10]; // 创建了一个 int 型的数组,有 10 个元素
double[] averages = new double[20];
  • 元素个数必须给出
  • 元素个数必须是整数
  • 元素个数可以是变量 :先让用户输入数组的个数,然后将这个数确定为数组的元素个数
  • 直接初始化,用大括号给出数组的所有元素的初始值。
int[] scores = {87,98,69,54,65,76,87,99};
  • 数组大小不需要给出
  • 可以用 length 获得数组大小

# 数组元素

numbers[0];// 表示数组中的第一个元素,每个元素是一个 int 类型的变量
  • 数组的索引或下标都是从 0 开始的

    源自于 C 语言,其编译器从 0 开始更易于计算

  • 最小的下标是 0 ,最大的下标是 元素个数-1

    编译器不会检查下标是否有效。
    如果运行时出现了无效下标,会导致程序终止。

# 赋值

int[] a = new int[10];
a[0] = 5;
int[] b = a;
b[0] = 16;
System.out.println(a[0]); // 输出结果为:16
int[] a1 = {1,2,3,4,5}; // step1
int[] a2 = a1; // step2
for ( int i=0; i<a2.length; ++i ) {
    a2[i] ++; // step3
}
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 循环

for(<类型><变量>:<数组>){
    ...
}
  • 数组中的每一个元素取出来作为这个类型的变量
  • 非常适用于遍历读出数组,但是不能修改数组,因为只能读出数组中的某一元素,但不知道索引值。
// 在给定的数据中,查找某个数据是否存在
int[] data = {2,3,4,5,6,7,8,9,10};
int x = in.nextlnt();
boolean found = false;
for(int k : data) {
    // 对于 data 数组中的每一个元素,循环的每一轮将其取出作为一个 k。
    // 所以每一轮的 k 都是变化的,第一轮 k=data [0],第二轮 k=data [2]...
    if(x == k) {
        found = true;
        break;
    }
}
if( found ) {
    System.out.println(x+"在其中");
} else {
    System.out.println(x+"不在其中");
}

# 例子

# 判断是否为素数

  • 方案一:从 2x-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: 去掉偶数后,从 3x-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+"不是素数");
}

# 构造素数表

  • 方案 1:构造前 50 个素数的表
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; // 只有素数才会被赋值
    // 执行顺序:primes [cnt] = x; cnt++;
}
//for-each 遍历输出所有元素值
for(int k:primes) {
    System.out.print(k+" ");
}
  • 方案 2:构造 100 以内的素数表
Scanner in = new Scanner(System.in);
boolean[] isPrime = new boolean[100]; // 初始化时,所有元素 = false
for(int i = 0; i < isPrime.length; i++) {
    isPrime[i] = true; // 遍历后全部赋值为 true
}
for(int i = 2; i < isPrime.length; i++) {
    if(isPrime[i]) { // 如果 i 没有被标记为非素数
        for(int k = 2; i * k < isPrime.length; k++) {
            // 将 2i、3i、4i 直至 ai < n 的数标记为非素数
            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 列上的单元
    • 不存在 a[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");
    }
}

# 小测验

  1. 若有定义: int a[2][3]; ,则以下选项中不越界的正确的访问有:

    • a[2][0]
    • a[2][3]
    • a[0][0]
    • a[0][3]
  2. 以下程序片段的输出结果是:

    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]);
    }
    • 369
    • 不能编译
    • 123
    • 运行时下标越界

# 编程题

# 题目 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 ); // 幂为 0 时,当前多项式结束
        }
        
        for (int j = 100; j >= 0; j--) { // 从高到低
            if( poly[j] != 0 ) { // 系数不为 0 的则显示
                
                if (!isFirst && poly[j] > 0) { // 非首个,且系数和大于 0,添加 + 
                    System.out.print("+");
                }
                
                if (poly[j] != 1) { // 系数为 1 时,不显示系数和                
                    if(poly[j] == -1) {
                        System.out.print("-"); // 系数为 - 1 时,只显示 -
                    } else {
                        System.out.print(poly[j]); // 显示 系数和
                    }
                }
                
                // 幂为 0 时 不显示 x 和幂值,幂为 1 时不显示幂值
                if (j > 0) {                    
                    System.out.print("x");                    
                    if (j > 1) {                        
                        System.out.print(j); // 显示 幂值
                    }
                }
                
                isFirst = false; // 第一轮输出后,赋值为非首个
                
            }
        }
        
    }
}
阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Ruri Shimotsuki 微信支付

微信支付

Ruri Shimotsuki 支付宝

支付宝

Ruri Shimotsuki 贝宝

贝宝