数组
数组
数组的概述:
一组存储相同数据类型的容器
数组的本质也是一个变量,用来存储一组变量的容器
格式:
数据类型[] 数组名 = new 数据类型[数组的长度]; // Java写法
变式:
数据类型 数组名[] = new 数据类型[数组的长度]; // C语言写法
**new: **在堆区分配内存空间
**数组的长度: **表示数组可以存放多少个连续的变量
变量的三要素:
1.声明
2.赋值
3.使用
数组的声明: 表示告诉计算机开辟多大的连续的内存空间
**数组的赋值: **地址传递
数组的使用: 访问数组中的元素
如何来访问数组中的元素:
通过下标、索引
数组名[索引]
索引范围 [0,数组的长度)
ArrayIndexOutOfBoundsException
- 异常名称: 数组索引越界异常
- 产生原因: 访问了不存在的索引
- 解决办法: 检查索引是否在 [0,数组的长度) 的范围内
NullPointerException
- 异常名称: 空指针异常
- 产生原因: 引用类型的变量没有 new,就访问了对象的成员或者访问了数组的元素
- 解决办法: 找到错误代码对应的那一行,观察哪些是引用类型,再观察这个引用类型有没有new
数组的初始化
**1.静态初始化:**
初始化的同时给数组的每一个元素赋值,不需要指明数组的长度,系统根据元素的个数动态计算数组的长度
**格式:**
格式一:数据类型[] 数组名 = {元素1, 元素2, 元素3, ... , 元素n};
格式二:数据类型[] 数组名 = new 数据类型[] {元素1, 元素2, 元素3, ... , 元素n};
有了格式一为什么有格式二? --> 在传递参数的时候,如果是匿名数组必须使用格式二
**2.动态初始化:**
初始化的同时由系统为每一个元素赋值即null值,必须指明数组的长度,赋值的特点满足堆区的默认值特点
堆区中每个变量都有默认值
byte short int long 默认值 0
float double 默认值 0.0
char 默认值 '\u0000' 就是一个空字符
boolean 默认值 false
引用类型 默认值 null
**格式:** 数据类型[] 数组名 = new 数据类型[数组的长度]; // Java写法
**变式: **数据类型 数组名[] = new 数据类型[数组的长度]; // C语言写法
面试题: 静态初始化和动态的初始化的区别?
数组的遍历:
遍历数组中的每一个元素
系统提供了一个 Arrays 工具类,能够直接帮助我们遍历 任意类型的 数组
值传递和引用传递(经典面试题)
**方法调用的时候: **
形式参数可以是如下类型
八大基本数据类型: 数值本身
引用数据类型: 地址
方法调用前a的值: 10
方法中的参数a的值: 15
方法调用后a的值: 10
方法调用前数组中所有元素的值: [11, 22, 33]
方法调用中数组中所有元素的值: [11, 300, 33]
方法调用中数组中所有元素的值: [11, 300, 33]
值传递和引用传递的区别:
值传递本质传递的是数值,引用传递传递的是地址
值传递是针对数组本身的副本,而引用传递是地址的副本
public static void main(String[] args) {
// test1();
// test2();
int[] arr = {11, 22, 33};
int[] arr2 = {44, 55, 66};
int[] arr3 = arr;
System.out.println(Arrays.toString(arr)); // [11, 22, 33]
System.out.println(Arrays.toString(arr2)); // [44, 55, 66]
System.out.println(Arrays.toString(arr3)); // [11, 22, 33]
arr3[1] = 500;
System.out.println(Arrays.toString(arr)); // [11, 500, 33]
System.out.println(Arrays.toString(arr2)); // [44, 55, 66]
System.out.println(Arrays.toString(arr3)); // [11, 500, 33]
}
private static void test2() {
int[] arr = {11, 22, 33};
System.out.println("方法调用前数组中所有元素的值: " + Arrays.toString(arr));
change(arr);
System.out.println("方法调用后数组中所有元素的值: " + Arrays.toString(arr));
}
public static void test1() {
int a = 10;
System.out.println("方法调用前a的值: " + a); // 10
change(a);
System.out.println("方法调用后a的值: " + a);
}
public static void change(int a) {
a += 5;
System.out.println("方法中的参数a的值: " + a); // 15
}
public static void change(int[] arr) {
arr[1] = 300;
System.out.println("方法中数组的所有元素的值: " + Arrays.toString(arr));
}
foreach遍历
数组和集合的专属迭代器
是for循环的简化
擅长遍历
语句格式:
for(元素类型 元素变量 : 遍历对象){
使用元素变量
}
:happy:注意:遍历的如果是多个数组,那么元素类型为int[],即遍历多个数组,那么每一个元素变量即为一个数组,所以不能用int来修饰
对比二者的区别:
1.foreach相比普通for,更简洁
2.foreach没有索引,普通for有索引,可以自定义索引
3.foreach的本质还是普通for
动态初始化的快速初始化方式
1.通过键盘输入
`for (int i = 0; i < arr.length; i++) {
System.out.print("请输入第" + (i+1) + "个数: ");
arr[i] = input.nextInt();`
2.通过随机数
`for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 100);
}
System.out.println(Arrays.toString(arr));`
数组的常见思想_遍历_求和_求最值_倒置
- 遍历:
arraytoString - 求和:
1、定义求和变量
2、遍历数组,累加求和 - 求最值:
有求和,求阶乘,统计思想,
1、假定第一个值为最大值
2、遍历数组的每一个元素
3、如果数组中有元素比假定的数大,那么此值赋值给最大值,然后再用此值进行之 后的数比较
4、循环结束max即为最大值 - 倒置:
思想eg:
int temp=0;
temp=arr[i];
arr[i]=arr[arr.length-1-i];
arr[arr.length-1-i]=temp;
排序算法
冒泡排序法:
相邻两个元素进行比较,大的数往后面放,每套比较完毕之后,最大的数就放在最后面
关键代码:
for(int i=0;i<arr.length-1;i++){ for(int j=0;j<arr.length-1-i;j++){ if(arr[j]>arr[j+1]){ int temp=0; temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } }
选择排序法:
从最左边开始,依次和后面的所有的元素进行比较,小的数往前移动,每一趟比较完毕后,最小的数出现在最前面
关键代码:
for(int i=0;i<arr.length-1;i++){ for(int j=i+1;j<arr.length;j++){ if(arr[j]<arr[i]){ int temp=0; temp=arr[j]; arr[j]=arr[i]; arr[i]=temp; } } }
可变参数
为什么需要有可变参数? -- 针对参数的类型一致,但是个数不一致的情况使用
格式:
参数类型… 变量名
可变参数的特点:
1.可变参数本质是数组
2.可变参数的 … 可以出现在 参数类型 和 变量名的 任意位置
3.可变参数必须出现参数列表的最后
eg:
int sum = 0;
for (int i : args) {
sum += i;
}
return sum;
}
计算多个int类型的和一个double类型的值的和
public static int add(double num, int... args) {
int sum = 0;
for (int i : args) {
sum += i;
}
return sum;
}
查找
基本查找:
关键代码:
public static int basicSearch(int[] arr, int num) { for (int i = 0; i < arr.length; i++) { if (num == arr[i]) { return i; } } return -1; }
二分查找:
前提条件:只能针对已经排好序的数据进行查找
思想:每次都实现查找数据中的中间那个元素,将要查找的数和中间索引位置处那个数比较,如果比mid索引数大,往右面找,min索引加1,mid=min+max/2;以这种方式,查找可以减少至少一半的效率
关键代码:
public static int binarySearch(int[] arr, int num) { // 1.定义最大索引和最小索引 int max = arr.length - 1; int min = 0; // 2.计算中间索引 int mid = (max + min) / 2; // 3.拿中间索引所对应的值和要查找的元素进行比较 while (arr[mid] != num) { /* * 大了 在左边找 * 小了 在右边找 */ if(arr[mid] > num) { max = mid - 1; } else if(arr[mid] < num) { min = mid + 1; } if (min > max) { return -1; } mid = (max + min) / 2; } // 相等就直接返回中间索引 return mid; }
二维数组
>概念: 本质上就是一个存放了一维数组的数组
注意:
Java中并没有真正意义上的二维数组,本质上就是一个存放了一维数组的数组
数组中的每一个元素还是一个数组,那么二维数组中每一个元素(此元素为一维数组)的值应该是地址值
格式1:
int[] arr = new int[m]; int[][] arr2 = new int[m][n];(标准格式)
格式2:
int arr[][] = new int[m][n];
格式3:
int[] arr[] = new int[m][n];
方法和数组的总结
方法
1.完成特定功能的代码片段
在其他语言里面成为 函数 y = f(x,y,z)
2.格式
访问权限修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…){
方法体;
return 返回值;
}
3.书写方法的位置
在类体以内,方法体以外
方法是不能嵌套定义
和main方法是平级关系,main方法是虚拟机调用的,那么我们书写的方法应该是在main方法中调用
4.书写方法的三要素
a.返回值类型
b.参数列表
c.方法名称
5.调用方法的三要素
a.方法需要什么参数我们就对应传什么参数
b.返回什么类型就用什么类型接收
c.方法的形参和实参的个数,顺序,类型要完全对应
6.调用方法的三种方式
a.直接调用(适用于返回类型为void的情况)
b.输出调用(适用于不需要获取到结果的情况)
c.赋值调用(适用于需要获取到结果并且后续可能使用这个方法计算的结果)
7.注意事项
a.方法如果我们不调用是不可能执行的
b.方法不能嵌套定义,方法之间是兄弟关系
c.如果一个方法没有返回值,那么定义的时候书写void关键字
d.如果一个方法有返回值,那么在书写方法体时候可以先返回一个默认值 返回int return 0
8.方法的重载
概念: 发生在同一个类中,方法名称相同,与返回值无关,参数的个数,顺序,类型不同构成重载
作用:
1.解决方法名重名问题
2.方便调用
注意: 方法的重载同时也是多态的一种表现形式
9.方法的递归
递归: 方法中调用方法,自己调自己
特点:
1.递归一定要有出口,如果没有出口,会出现死递归,死递归会造成程序崩溃,而死循环不会
2.构造方法不能够递归
3.递归一般慎用,但是在文件遍历或者层级不确定情况下可以使用,有奇效
案例:
1.递归求阶乘
2.斐波那契数列
数组:happy:
1.存储相同数据类型的一组连续的数据
2.数组的特点
a.数组本身也是一个变量,既然是变量(局部变量),那么在栈区开辟空间,先声明再赋值再使用
b.数组的数据类型可以是八大基本数据类型和引用类型,数组本身是引用类型
c.创建数组我们需要使用到new,那么new出来的在堆区开辟,所以数组会同时在栈区和堆区开辟空间
d.如果一个数组没有指向堆区某块内存地址,这个时候数组变量为null,如果使用这个变量会出现空指针异常
e.如果一个数组访问了不存在的索引,会出现数组越界
3.格式
a.int[] arr = new int[5];
b.int arr[] = new int[5];
注意:int arr[] = new int[];是错误的
4.数组的初始化
a.静态初始化: 在定义数组的时候先给出元素,然后系统会根据元素的个数计算长度,这种初始化不会指定数组的长度
int[] arr = {11,22,33,44,55};
int[] arr = new int[]{11,22,33,44,55};
b.动态初始化: 在定义数组的时候默认值为堆区变量的默认值,需要给出数组的长度
int[] arr = new int[5]; 默认值是0
5.数组的内存分配(能够自己画图分析)
内存分为:
a.栈区: 先进后出,类似于子弹夹,一般用来给局部变量开辟空间
b.堆区: 用于存储new出来的对象
堆区创建出来的对象都会有地址值,而数组变量就是用来存放这个地址的
凡事new出来的对象都有默认值
byte short int long 0
float double 0.0
char ‘\u0000’
boolean false
引用类型 null
堆区一旦被赋值为null的时候,原来的内存空间不会被立刻回收,而是在垃圾回收器空闲的时候回收
int[] arr = new int[5];
arr = null;
c.方法区
静态区
常量池
6.数组的遍历
遍历: 获取数组中的每一个元素
public static void printArr(int[] arr){
for(int i= 0; i < arr.length; i++){
System.out.println(ar[i]);
}
}
7.数组的动态快速初始化 (键盘输入 + 数组的动态初始化 + 数组的遍历)
Scanner input = new Scanner(System.in);
System.out.println(“请输入学生的人数:”);
double num = input.nextDouble();
double[] arr = new double[num];
for(int i = 0; i < arr.length; i++){
System.out.print(“请输入第” + (i+1) + “个学生的成绩”);
arr[i] = input.nextDouble();
}
input.close();
8.数组的基本操作
1.数组的遍历 就是获取数组中的每一个元素
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
2.求和求平均值
double sum = 0.0;
for(int i = 0; i < arr.length; i++){
sum += arr[i];
}
double average = sum / arr.length;
3.求最值
最值思想: 假设第一个数为最大值max,遍历获取到数组的每一个元素
拿到每一个元素和这个max进行比较
如果比假定的最大值还要大,那么将该数赋值给最大值
public static int getMax(int[] arr){
int max = arr[0];
for(int i = 0; i < arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
}
return max;
}
4.数组的倒置
public static void reverseArray(int[] arr){
for(int i = 0; i < arr.length / 2; i++){
int temp = 0;
temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
}
5.数组的排序
冒泡排序
public static void bubbleSort(int[] arr){
for(int i = 0; i < arr.length - 1; i++){
for(int j = 0; j < arr.length - 1 - i; j++){
if(arr[j] > arr[j+1]){
int temp = 0;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;}}
}
}
选择排序
public static void selectSort(int[] arr){
for(int i = 0; i < arr.length; i++){
for(int j = i+1; j < arr.length; j++){
if(arr[j] > arr[i]){
int temp = 0;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;}}}
}
6.查找
基本查找(针对无序的)
public static int basicSearch(int[] arr, int num){
for(int i = 0; i < arr.length; i++){
if(num == arr[i]){
return i;}
}
return -1;
}
二分法查找(针对有序的)
public static int binarySearch(int[] arr, int num){ int max = arr.length - 1; int min = 0; int mid = (max + min) / 2; while(arr[mid] != num){ if(arr[mid] > num){ max = mid - 1; } else if(arr[mid] < num){ min = mid + 1; } if(min > max){ return -1; } mid = (max + min) / 2; } return mid; }
7.使用Arrays工具类进行快速查找和排序
1.对数组元素进行输出
public static String toString(int[] arr)
2.对数组进行排序
public static void sort(int[] arr); 采用的是快速排序法
3.对数组进行二分法查找
public static int binarySearch(int[] arr, int key)
二维数组
二维数组概念: 本质是存放了一维数组的数组
数组的格式
格式1: int[][] arr = new int[m][n]; (内存图)
格式2:int arr[][] = new int[m][n];
格式3: int[] arr[] = new int[m][n];
格式3: int[][] arr = new int[m][]; (内存图)
初始化:
静态初始化
int[][] arr = new int[][]{{11,22,33},{44,55},{66}};
int[][] arr = {{11,22,33},{44,55},{66}};
动态初始化
int[][] arr = new int[m][n]; (内存图)
int[][] arr = new int[m][]; (内存图)
二维数组的遍历
for(int i = 0; i < arr.length; i++){ for(int j = 0; j < arr[j].length; j++){ System.out.println(arr[i][j]); } }
常用的案例:
1.求各个班级的总成绩
2.打印杨辉三角(两种格式)
1883

被折叠的 条评论
为什么被折叠?



