二维数组
- 二维数组概述
可以理解成数组嵌套数组;如班级里64个人,8个人组成一个一维数组,同时一维数组又可以组成一个二维数组,二维数组就是一个班。 - 二维数组格式
数据类型[][] 变量名 = new 数据类型[m][n];
m表示这个二维数组有多少个一维数组 必须写上
n表示每一个一维数组的元素个数 可写可不写; - 举例:
int[][] arr = new int[3][2];
定义了一个二维数组arr
这个二维数组有3个一维数组,名称是arr[0],arr[1],arr[2]
每个一维数组有2个元素,可以通过arr[m][n]来获取
表示获取第m+1个一维数组的第n+1个元素
案例
案例一:
public class ArrayDemo {
public static void main(String[] args) {
int[][] arr=new int[3][2];
System.out.println(arr[0]);
System.out.println(arr[0][0]);
}
}
注意
- 二维数组动态初始化,由我们给出数组长度,JVM开辟空间赋默认值;
- 创建一个二维数组,3 表示二维数组,表示这个二维数组里面,放了3个一维数组,2 表示二维数组中的一维数组的长度;
- 清楚程序运行内存图:
案例二:
public class ArrayDemo2 {
public static void main(String[] args) {
int[][] arr= new int[3][];
System.out.println(arr[0]);
}
}
注意
二维数组中,对于所包含的一维数组长度可以不填,但二维长度必须填;
内存流程图:
案例三:
public class ArrayDemo2 {
public static void main(String[] args) {
int[][] arr = new int[3][2];
arr[0]=new int[]{10,20,30};
arr[1]=new int[]{100,200};
arr[2]=new int[]{1,2,3};
System.out.println(arr);//二维数组的地址值
System.out.println(arr[0]);//第一个一维数组的地址值
System.out.println(arr[1]);//第二个一维数组的地址值
System.out.println(arr[2]);//第三个一维数组的地址值
// System.out.println(arr[3]);// 角标越界
System.out.println(arr.length); //二维数组的长度
System.out.println(arr[0].length);//二维数组中的第一个一维数组的长度
//取出数组具体的值
System.out.println(arr[0][2]);
System.out.println(arr[2][2]);
}
}
案例四:
public class ArrayDemo3 {
public static void main(String[] args) {
//创建三个一维数组
int[] arr1 = new int[2];
int[] arr2 = new int[2];
int[] arr3 = new int[2];
//把上面三个一维数组存到二维数组里面去
int[][] maxarr = new int[3][];
maxarr[0] = arr1;
maxarr[1] = arr2;
maxarr[2] = arr3;
System.out.println(maxarr[maxarr.length - 1][arr3.length - 1]);
}
}
注意
最后输出maxarr[2][1];
案例五:
public class ArrayDemo {
public static void main(String[] args) {
//二维数组静态初始化
int[][] arr=new int[][]{{2,4},{10,30},{10,30,40},{10,1}};
System.out.println(arr.length);
System.out.println(arr[3][1]);
//简写方式
int[][] arr2 ={{2, 4}, {10, 30}, {10, 30, 40}, {10, 1}};
System.out.println(arr2.length);
System.out.println(arr2[2][2]);
}
}
案例六:
public class ArrayDemo2 {
public static void main(String[] args) {
int[][] arr1= new int[2][2];
int[][] arr2 = new int[2][2];
int[][] arr3 = new int[2][2];
arr1[0][0]=10;
arr2[1][1]=100;
arr3[1][1]=100;
arr3=arr1;
arr1[0][1]=1000;
System.out.println(arr1[0][0]);//10
System.out.println(arr1[0][1]);//1000
System.out.println(arr2[0][0]);//0
System.out.println(arr2[0][1]);//0
System.out.println(arr3[0][0]);//10
System.out.println(arr3[0][1]);//1000
}
}
注意
程序运行过程的内存图需要清楚;
案例七:
二维数组的遍历
public class ArrayDemo {
public static void main(String[] args) {
int[][] arr = {{2, 4}, {10, 30}, {10, 30, 40}, {10, 1}};
//二维数组的遍历
for (int i = 0; i < arr.length; i++) {
//System.out.println(arr[i]); //一维数组
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
}
}
案例八:
需求:公司年销售额求和
//某公司按照季度和月份统计的数据如下:单位(万元)
//第一季度:22, 66, 44
//第二季度:77, 33, 88
//第三季度:25, 45, 65
//第四季度:11, 66, 99
public class ArrayDemo2 {
public static void main(String[] args) {
//数组长度过大会造成堆内存溢出
// int[] arr = new int[900000000];
int[][] arr = {{22, 66, 44}, {77, 33, 88}, {25, 45, 65}, {11, 66, 99}};
//遍历二维数租,求和
int sum = 0;
for (int i = 0; i < arr.length; i++) {
//System.out.println(arr[i]);
for (int j = 0; j < arr[i].length; j++) {
sum += arr[i][j];
}
}
System.out.println("总销售额:" + sum);
}
}
案例九:
-
需求:打印杨辉三角形(行数可以键盘录入)
//1
//1 1
//1 2 1
//1 3 3 1
//1 4 6 4 1
//1 5 10 10 5 1 -
分析规律:
1.每一行的第一个数和最后一个数都是1
2.从第三行开始,中间的数等于我上一行的前一列的数和我上一行本列的数之和; -
怎么做?通过二维数组,存储这种行列结构的数据
你要打印出三角形
1.第一个数和最后一个数都是1
2.第三行开始,中间的数等于我上一行的前一列的数和我上一行本列的数之和;
import java.util.Scanner;
public class ArrayDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入行数");
int n = sc.nextInt();
int[][] arr=new int[n][n]; //定义一个数组,行列数都一样
for (int i = 0; i < arr.length; i++) {
arr[i][0]=1; //将每一行的第一个数,置成1
arr[i][i]=1; //将三角形的每一行的最后一个元素置成1
}
//计算中间元素
for (int i =2; i < arr.length; i++) {
for (int j =1; j <= i-1; j++) {
//第三行开始,中间的数等于我上一行的前一列的数和我上一行本列的数之和
arr[i][j]=arr[i-1][j-1]+arr[i-1][j];
}
}
//遍历二维数组
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j <=i; j++) {
System.out.print(arr[i][j]+"\t");
}
System.out.println();
}
}
}
递归解决问题的思想
- 递归:在Java中值的是,在方法中调用方法本身的这种现象,我们称之为递归;
生活中的递归:从前有座山,山上有座庙,庙里有个老和尚给小和尚讲故事…
学Java—找工作—挣钱—娶媳妇—生娃—学Java—找工作—挣钱—取媳妇 - 递归体现的思想:递归所体现的思想,就是拆分合并的思想;
案例
案例一:
public class MyTest {
public static void main(String[] args) {
test(9);
}
//private static void test() {
// System.out.println("这是一个死递归");
// // 栈溢出错误
// test();
//}
private static void test(int i) {
System.out.println("这是递归调用");
if (i < 0) {
return;
} else {
test(i - 1);
}
}
}
- 注意:
递归注意的事项:
- 递归要有出口,没有出口就是死递归,死递归会造成栈溢出;
- 递归的次数不宜过多,过多也会造成栈溢出。
- 递归所体现的思想:拆分合并的思想
案例二:
- 问题:求 5的阶乘 5!=54321;
public class MyTest {
public static void main(String[] args) {
// int jiecheng=5*4*3*2*1;
//循环做
int r=1;
for (int i = 1; i <= 5; i++) {
r*=i;
}
System.out.println(r);
}
}
普通方法;
public class MyTest2 {
public static void main(String[] args) {
//求 5的阶乘
//用递归来做
int r= jieCheng(5);
System.out.println("结果是"+r);
}
private static int jieCheng(int i) {
if(i==1){
return 1;
}else{
return i*jieCheng(i-1);
}
}
}
注意采用递归思想;
- 思路图示:
二维数组的遍历
案例
-
案例演示:
需求:兔子问题(斐波那契数列)
有一对兔子,从出生后第3个月起每个月都生一对兔子,
小兔子长到第三个月后每个月又生一对兔子,
假如兔子都不死,问第二十个月的兔子对数为多少? -
分析;
////月份 兔子的对数 // 1 1 // 2 1 // 3 2 // 4 3 // 5 5 // 6 8 // 7 13 // 8 21 // 1 1 2 3 5 8 13 21 从第三个数开始,这个数等于前两个数之和 (斐波那契数列) //采用普通方法来做,到第20个月有多少对兔子
public class MyTest {
public static void main(String[] args) {
////二维数组:就是数组的元素是一维数组,那么这个数组就是二维数组
//int[][] arr=new int[3][2];
//int[][] arr2=new int[2][];
//int[][] arr3={{10},{20}};
int[] arr=new int[20];
arr[0]=1;
arr[1]=1;
for (int i =2; i < arr.length; i++) {
arr[i]=arr[i-1]+arr[i-2];
}
System.out.println("兔子的对数"+arr[19]);
}
}
注意采用普通方法解决
public class MyTest2 {
public static void main(String[] args) {
//递归来做
int sum = sumRabbit(20);
System.out.println("兔子的对数" + sum);
}
private static int sumRabbit(int i) {
if (i == 1 || i == 2) {
return 1;
} else {
return sumRabbit(i - 1) + sumRabbit(i - 2);
}
}
}
java 中的参数传递问题
- 基本数据类型,作为参数传递,形参的改变,不影响实参
- 引用数据类型,作为参数传递,形参的改变,会影响实参
public class MyTest {
public static void main(String[] args) {
//定义两个变量
int a = 10;
int b = 20;
//输出两个变量的值
System.out.println("a: " + a + ",b: " + b); //1. 10 20
//调用方法,传入参数
change(a, b);
//输出变量的值
System.out.println("a: " + a + ",b: " + b); //4. 10 20
//定义一个数组
int[] arr = {1, 2, 3, 4, 5};
//调用方法,传入数组
change(arr);
//输出数组第二个元素的值
System.out.println(arr[1]); //5.4
//局部变量:定义在方法中的变量,或者方法声明上的变量(形参)。
//局部变量存在栈内存
}
public static void change(int a, int b) {
System.out.println("a: " + a + ",b: " + b); //2. 10 20
a = b;
b = a + b;
System.out.println("a: " + a + ",b: " + b); //3. 20 40//思考区别输出显示和返回值
}
public static void change(int[] arr) {
//遍历数组
for (int x = 0; x < arr.length; x++) {
if (arr[x] % 2 == 0) {
arr[x] *= 2; //思考返回值和输出显示区别
}
}
}
}