数组&递归
数组概述
-
数组类似于一个容器,是内存空间中开辟出来的一个区域,这个区域用来存储多个同一数据类型的数据,这样避免了当大量变量数据需要使用时需要对每个数据进行声明。只要是数据类型相同都可以放进同一个数组空间。此时每个数据都称为这个数组内的元素。
-
常用的数组分为一维数组和二维数组,当然也存在三维数组,但是在日常应用中我们应用最多的时一维数组和二维数组。
注意:数组是存储多个变量(元素)的缓存空间(容器),同一数组内元素变量的数据类型一致
一维数组
-
声明一维数组的语法格式
数组元素类型 数组名字[];int arr[];
-
数组元素类型[] 数组名字;
String str[];
数组声明后还无法直接访问他的元素,因为你只是声明了一个int型的名叫arr的数组,但是并没有为数组分配内存空间,这时我们需要用new关键字来为数组分配内存空间。
-
数组名称 = new 数组元素的类型[数组元素的个数]
-
new关键字为数组分配内存时
整形数组的初始值都为0
浮点型数组的初始值都是0.0
布尔类型的初始值都是false
char型数组的初始值都是空格字符(\u0000*)
定义一个数组的日常使用语法格式是:数据类型[] = 数组名=new 数组类型[数组长度];
数组初始化
为数组中的数组元素分配内存空间,并为每个数组元素赋值
案例演示
案例A:打印数组
public class array {
public static void main(String[] args) {
int[] arr = new int[3];
arr[0]=10;
arr[1]=20;
arr[2]=30;
System.out.println(arr); //打印arr数组地址
for(int i=0;i<=arr.length-1;i++){
System.out.println(arr[i]);
}
}
}
Java中内存分配以及栈(Stack)和堆(Heap)的区别
-
栈内存:用于存储局部变量,当数据使用完后,所占空间会自动释放
-
堆内存
1、数组和对象,通过new建立的实例都存放在堆内存内 2、每个实体都有内存地址值 3、实体中的变量都有默认初始化值 4、实体不被使用会在不确定的时间内被垃圾回收器回收
-
一维数组内存图解
二维数组
什么是二维数组?
二维数组就是有一个一维数组a,这个a中的每一个元素都是一个一维数组,此时我们称其为二维数组(学过线性代数的都知道,其实二维数组可以看做定义了一个m行n列的矩阵)
二维数组的语法格式
格式一:
数据类型[][] 变量名 = 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个元素
格式二:
数组类型[] [] 变量名 = new 数据类型[m] [];
m表示这个二维数组中一维数组的个数
这次没有给出一维数组元素的个数,可以动态给出
int[][] arr = new int[3][]; //引用数据,内赋值null
arr[0] = new int[2]; //这里给arr[0],arr[1],arr[2]的是地址
arr[1] = new int[5];
arr[2] = new int[4];
格式三
数据类型[] [] 变量名 = new 数据类型[] []{{元素……},{元素……},{元素……},{元素……}···};
简化版:
数据类型[] [] 变量名 = {{元素……},{元素……},{元素……}};
这个格式属于静态初始化,由我们指定具体元素值,由系统分配长度
注意事项
以下格式也可以表示二维数组
a:数据类型 数组名[][] = new 数据类型[m][n];
b:数据类型[] 数组名[] = new 数据类型[m][n];
这两种格式不推荐使用
注意下面定义的区别
int x,y;
int[] x,y[];
区别是:
int[] x,y[];//定义了两个数组 一个是一维数组x 一个是二维数组y
x=new int[3];
y=new int[3][];
案例演示
-
定义一个二维数组,输出二维数组的名称和二维数组的的每一个一维数组,然后动态给二维数组赋值一维数组
再次输出二维数组中的每一个一维数组,给二维数组中的元素赋值,输出对应的元素值
-
public class TwoDimension { public static void main(String[] args) { System.out.println("------------二维数组的创建及使用-----------"); System.out.println("--初始化二维数组--"); //动态初始化,指定长度 //格式一 int arrDemo1[][] = new int[3][4]; //格式二 int[][] arrDemo3=new int[3][]; arrDemo3[0]=new int[2]; arrDemo3[1]=new int[5]; arrDemo3[2]=new int[4]; //格式三 //静态初始化,JVM自动分配内存长度 int arrDemo2[][] = {{1}, {2, 3}, {4, 5, 6}}; //输出第一个二维数组的地址 System.out.println(arrDemo1); System.out.println(); //将二维数组arrDemo1中的第二个一维数组中的第四个元素赋值5 arrDemo1[1][3] = 5; //输出二维数组的两个元素 System.out.println(arrDemo1[1][3]); System.out.println(arrDemo1[0][2]); //遍历输出第一个二维数组,结果为0阵列,其中第三行,第四列为5 //二维数组的遍历是需要两个循环嵌套,外循环作为行遍历,内循环作为列遍历 for (int i = 0; i <= arrDemo1.length - 1; i++) { for (int j = 0; j <= arrDemo1[i].length - 1; j++) { System.out.print(arrDemo1[i][j]); } System.out.println(); } System.out.println(); //输出arrDemo2 for (int i = 0; i <= arrDemo2.length - 1; i++) { for (int j = 0; j <= arrDemo2[i].length - 1; j++) { System.out.print(arrDemo2[i][j]); } System.out.println(); } System.out.println(); //输出arrDemo1的以为变量地址 for (int i = 0; i <= arrDemo1.length - 1; i++) { System.out.println(arrDemo1[i]); } } }
-
输出杨辉三角
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1
import java.util.Scanner;
public class myTest2 {
public static void main(String[] args) {
/*需求:打印杨辉三角形(行数可以键盘录入)
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1*/
/*分析:杨辉三角的特点
* 1、每一行的首,尾都是1
* 2、从第三行开始,每一行的中间数字=同一列上一行的数字+前一列上一行的数字*/
Scanner sc = new Scanner(System.in);
System.out.println("请录入行数");
int n = sc.nextInt();
int num[][] = new int[n][n];
//第一个和最后一个都是1
for (int i = 0; i < num.length; i++) {
num[i][0] = 1;
num[i][i] = 1; //num[i][num[i].length-1]=1; 不对
}
//从第三行开始才有中间值
// 中间值的算法,从第三行开始,中间的值=同列上一行+上一行前一列
for (int i = 2; i < num.length; i++) {
for (int j = 1; j < i; j++) {
num[i][j]=num[i-1][j]+num[i-1][j-1];
}
}
//打印三角形
for (int i = 0; i < num.length; i++) {
for (int j = 0; j <= i; j++) {
System.out.print(num[i][j]+" ");
}
System.out.println();
}
}
}
数组的操作
数组的操作包括获取最值,遍历,反转,查表法,基本查找
案例:利用建立功能方法并且调用,实现数组内求最大值,最小值,打印数组元素,将数组内元素反转
//数组遍历循环的快捷键arr.length-1.forr
//数组反向遍历
/*for(i=length-1;i>=0;i--)*/
public class MyTest {
public static void main(String[] args) {
int[] arr={100,200,300,400,500,600,50};
int max=getMax(arr);
System.out.println(max);
int min=getMin(arr);
System.out.println(min);
showArr(arr);
reversalArr(arr);
}
//计算最大值
public static int getMax(int[] arr){
int max=arr[0];
for(int i=0;i<=arr.length-1;i++){
if(max<arr[i]){
max=arr[i];
}
}
return max;
}
//计算最小值
public static int getMin(int[] arr){
int min=arr[0];
for(int i=0;i<=arr.length-1;i++){
if(min>arr[i]){
min=arr[i];
}
}
return min;
}
//打印数组元素
public static void showArr(int[] arr){
for(int i=0;i<=arr.length-1;i++){
System.out.print(arr[i] + ",");
}
System.out.println();
}
//反转数组元素
public static void reversalArr(int[] arr){
for (int i =0 ; i <= arr.length/2 - 1; i++) {
int t=0;
t=arr[i];
arr[i]=arr[arr.length-1-i];
arr[arr.length-1-i]=t;
}
for (int j = 0; j <= arr.length-1; j++) {
System.out.print(arr[j]+",");
}
//将数组内元素的位置调换(方法二)
/* for(int i=0,int j=arr.length-1;i<j;i++,j--){
}*/
System.out.println();
}
}
/*A:
* 案例演示:
* 根据键盘输入索引,查找对应星期*/
//查表法
//根据索引找对应元素
import java.util.Scanner;
public class MyTest2 {
public static void main(String[] args) {
String[] week = {"星期一", "星期二", "星期三", "星期四",
"星期五", "星期六", "星期天"};
Scanner sc=new Scanner(System.in);
System.out.println("请输入索引0-6");
int index=sc.nextInt();
String ele = getElement(index,week);
System.out.pringln(ele);
}
private static String getElement(int index ,String[] week){
if(index >= 0 && index <= 6){
String str = week[index];
return str;
}else{
return "error";
}
}
}
//根据元素查对应的索引
import java.util.Scanner;
public class MyTest3 {
public static void main(String[] args) {
String[] week = {"星期一", "星期二", "星期三", "星期四",
"星期五", "星期六", "星期日"};
//根据元素查对应的索引
Scanner sc = new Scanner(System.in);
System.out.println("请输入星期一----星期天");
String s = sc.nextLine();
int index = getNum(s, week);
System.out.println("该元素对应的索引是" + index);
}
private static int getNum(String s, String[] week) {
int index = -1;
for (int i = 0; i <= week.length - 1; i++) {
if (week[i].equals(s)) { //此处判断不能用week[i]==s,这样可能会出错
index = i;
break;
}
}
return index;
}
}
/*键盘输入月份
输出每个月有多少天*/
import java.util.Scanner;
public class myTest4 {
public static void main(String[] args) {
int dayNum[] = {31,28,31,30,31,30,31,31,30,31,30,31};
Scanner sc = new Scanner(System.in);
System.out.println("请输入月份");
int month = sc.nextInt();
int day = getDay(month,dayNum)-1;
System.out.println(month+"月有"+day+"天");
getDay(dayNum);
}
public static int getDay(int month,int[] dayNum){
if(month >= 0 && month <= 12){
int day = dayNum[month];
return day;
}else{
return 404;
}
}
public static void getDay(int[] dayNum){
for(int i = 0;i <= dayNum.length-1;i++){
System.out.println(i+1+"月有"+dayNum[i]+"天");
}
}
}
import java.util.Scanner;
public class MyTest {
public static void main(String[] args) {
/*A:案例演示
需求:分别输出公司各个季度的总销售额和年销售额
某公司按照季度和月份统计的数据如下:单位(万元)
第一季度:22,66,44
第二季度:77,33,88
第三季度:25,45,65
第四季度:11,66,99*/
int[][] annualSales=new int[4][3];
Scanner sc = new Scanner(System.in);
//输入销售额,并把销售额存入二维数组中,行代表季度,列代表月份
System.out.println("请输入销售额");
for(int i=0;i<=annualSales.length-1;i++) {
for (int j = 0; j <= annualSales[0].length - 1; j++) {
System.out.println("请输入第"+(i+1) +"季度第"+ (j + 1) + "个月的销售额");
int money = sc.nextInt();
annualSales[i][j] = money;
}
}
for(int i=0;i<=annualSales.length-1;i++) {
for (int j = 0; j <= annualSales[i].length - 1; j++) {
System.out.print(annualSales[i][j]+", ");
}
System.out.println();
}
//计算每个季度的收入
int yearSales=0;
for(int i=0;i<=annualSales.length-1;i++){
int addQuartSales=0;
for(int j=0;j<=annualSales[i].length-1;j++){
switch(i){
case 0: addQuartSales += annualSales[i][j];
break;
case 1: addQuartSales += annualSales[i][j];
break;
case 2: addQuartSales += annualSales[i][j];
break;
case 3: addQuartSales += annualSales[i][j];
break;
}
}
System.out.println("第"+(i+1)+"个季度的总收入为"+addQuartSales);
}
//计算全年总收入
for(int i=0;i<=annualSales.length-1;i++) {
for (int j = 0; j <= annualSales[i].length - 1; j++) {
yearSales+=annualSales[i][j];
}
}
System.out.println("全年总收入为"+yearSales);
}
}
参数传递问题
/*A:案例演示
看程序写结果,并画内存图解释*/
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("a: " + a + ",b: " + b); //a=10,b=20
change(a,b);
System.out.println("a: " + a + ",b: " + b); //a=10,b=20
int[] arr = {1,2,3,4,5};
change(arr); //arr[1]=4
System.out.println(arr[1]); //arr[3]=8
}
public static void change(int a,int b) {
System.out.println("a: " + a + ",b: " + b); //a=10,b=20
a = b; //a=20
b = a + b; //b=40
System.out.println("a: " + a + ",b: " + b); //a=20,b=40
}
public static void change(int[] arr){
for(int x = 0 ; x < arr.length ; x++){
if(arr[x]%2 == 0){
arr[x] *= 2;
}
}
}
/*基本类型的参数传递,属于值传递
* 引用类型的参数传递,是将地址值传递过去
* 特点:基本类型作为参数传递,形参的改变不影响实参
* 引用类型作为参数传递,形参的改变会影响实参*/
递归
/*递归:在方法中低啊用方法本身的一种现象
* 递归需要注意的:
* 1、递归要有出口,不然就是死递归,死递归会导致栈溢出
* 2、递归次数不宜过多,过多也会有栈溢出的可能
* 3、递归体现的是一种拆分合并的思想*/
因为JVM的栈内存大小是固定的,递归要是没有设置合适的出口,死递归就会造成栈溢出错误
递归就是将一个大问题进行拆分,使其变成若干个简单问题的综合,当解决了所有小问题之后,大问题也就解决了,以下画图进行解释
案例分析
- 计算5!
/*计算5!*/
public class factorial {
public static void main(String[] args) {
int r=multiplication(10);
System.out.println("结果:" + r);
}
private static int multiplication(int n){
if(n==1){
return 1;
}else{
return n*multiplication(n-1);
/*第一次:5*multiplication(4)
* 第二次:5*4*multiplication(3)
* 第三次:5*4*3*multiplication(2)
* 第四次:5*4*3*2*multiplication(1)
* 第五次:5*4*3*2*1,返回1*/
}
}
}
- 猴子第一天摘下N个桃子,当时就吃了一半,还不过瘾,就又多吃了一个。第二天又将剩下的桃子吃掉一半,又多吃了一个。以后每天都吃前一天剩下的一半零一个。到第10天在想吃的时候就剩一个桃子了,问第一天共摘下来多少个桃子?并反向打印每天所剩桃子数。
public class GetPeachNumber {
public static void main(String[] args) {
/* 第10天桃子数 1
* 第9天桃子数 (第10天桃子数+1)*2
* 第8天桃子数 (第9天桃子数+1)*2
* 第7天桃子数 (第9天桃子数+1)*2
* …… ……
* 第1天桃子数 (第2天桃子数+1)*2 */
int peachNumber=getPeachNumber(1);
System.out.println("第一天摘了"+peachNumber+"个桃子");
}
private static int getPeachNumber(int n){
if(n==10){
return 1;
}else{
int sum=0;
sum=(getPeachNumber(n+1)+1)*2;
System.out.println("第"+n+"天所剩桃子数为"+sum);
return sum;
}
}
}
- 需求:兔子问题(斐波那契数列)
有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?
由此可见兔子对象的数据是:1 , 1 , 2 , 3 , 5 , 8 …
public class rabbit {
public static void main(String[] args) {
/*A:案例演示: 需求:兔子问题(斐波那契数列)
有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?
由此可见兔子对象的数据是:1 , 1 , 2 , 3 , 5 , 8 ...*/
/*1 1
* 2 1
* 3 2
* 4 3
* 5 5
* 6 8
* ... ...
* 20 第19个月的兔子对数+第18个月的兔子对数 */
//递归思考问题需要从所需要求得的结果去思考规律与编程
int rabbitSum = getRabbitNumber(20);
System.out.println("第二十个月一共有" + rabbitSum + "对兔子");
//普通循环方法实现
int rabbit[] = new int[20];
rabbit[0] = 1;
rabbit[1] = 1;
getRabbitNumber(rabbit);
System.out.println(rabbit[19]);
}
private static int getRabbitNumber(int monthNumber) {
if (monthNumber == 1 || monthNumber == 2) {
return 1;
} else {
return getRabbitNumber(monthNumber - 1) + getRabbitNumber(monthNumber - 2);
}
}
private static void getRabbitNumber(int[] rabbit) {
for (int i = 2; i <= rabbit.length - 1; i++) {
rabbit[i] = rabbit[i - 1] + rabbit[i - 2];
}
}
}
- 有5个人坐在一起,问第5个人多少岁?
他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。
问第3个人,又说比第2人大两岁。
问第2个人,说比第1个人大两岁。最后
问第1个人,他说是10岁。
请问第5个人多大?
public class yearAge {
public static void main(String[] args) {
/*有5个人坐在一起,问第5个人多少岁?
他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。
问第3个人,又说比第2人大两岁。
问第2个人,说比第1个人大两岁。最后
问第1个人,他说是10岁。
请问第5个人多大?*/
/*分析:
* 1 10
* 2 第一人年龄+2
* 3 第二人年龄+2
* 4 第三人年龄+2
* 5 第四人年龄+2 */
System.out.println(getAge(5));
}
private static int getAge(int n){
int fiveAge=0;
if(n==1){
return fiveAge=10;
}else{
return fiveAge=(getAge(n-1)+2);
}
}
}
public class yearAge {
public static void main(String[] args) {
/*有5个人坐在一起,问第5个人多少岁?
他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。
问第3个人,又说比第2人大两岁。
问第2个人,说比第1个人大两岁。最后
问第1个人,他说是10岁。
请问第5个人多大?*/
/*分析:
* 1 10
* 2 第一人年龄+2
* 3 第二人年龄+2
* 4 第三人年龄+2
* 5 第四人年龄+2 */
System.out.println(getAge(5));
}
private static int getAge(int n){
int fiveAge=0;
if(n==1){
return fiveAge=10;
}else{
return fiveAge=(getAge(n-1)+2);
}
}
}