『零基础学Java语言-浙江大学-翁恺』第5周 数组

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

文章目录

  • 笔记
    • 数组
      • 数组变量
        • 定义与初始化
      • 数组元素
      • 赋值
      • 遍历
        • for 循环
        • for-each 循环
      • 例子
        • 判断是否为素数
        • 构造素数表
    • 二维数组
      • 遍历
      • 初始化
      • 例子
        • tic-tac-toe游戏
  • 小测验
  • 编程题
    • 题目1. 多项式加法(5分)
      • 解题代码

笔记

数组

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

数组变量

定义与初始化

  • 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]);
}

示意图:

step1
step2
step3
遍历修改a2
a2=a1
a1
{ 1, 2, 3, 4, 5 }
a1
{ 1, 2, 3, 4, 5 }
a2
a1
{ 2, 3, 4, 5, 6 }
a2

数组变量 ≠ 数组

  • 数组变量数组的管理者,而不是所有者,非数组本身
  • 数组必须创建出来,然后交给数组变量管理
  • 数组变量之间的赋值,是管理权限的赋予
  • 数组变量之间的比较,是判断是否管理同一个数组
  • 两个数组即使内容相同也不等同,判断两个数组是否相等,需遍历逐个元素
  • 复制数组,必须遍历源数组,将每个元素逐一拷贝给目的数组

遍历

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. a[2][0]
    B. a[2][3]
    C. a[0][0]
    D. a[0][3]

    C

  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]);
    }
    

    A. 369
    B. 不能编译
    C. 123
    D. 运行时下标越界

    A

编程题

题目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; // 第一轮输出后,赋值为非首个
				
			}
		}
		
	}
}

你可能感兴趣的:(自考笔记,#,04747Java语言程序设计)