1.数组的引出
为什么需要数组
一个有 养鸡场有 6 只鸡,它们的体重分别是 3kg,5kg,1kg,3.4kg,2kg,50kg 。
请问这六只鸡的总体重是多少?平
均体重是多少? 请你编一个程序。 Array01.java
思路:
定义 6 个变量 , 加起来 总体重, 求出平均体重.引出 -> 数组
数组介绍
数组可以存放多个同一类型的数据。数组也是一种数据类型,是引用类型。
即:数(数据)组(一组)就是一组数据
定义数组和方法:
double[] hens = {3, 5, 1, 3.4, 2, 50, 7.8, 88.8,1.1,5.6,100};
方法:数组名.length 得到数组的大小/长度
访问元素:hens[下标],第一个元素就是 hens[0]
遍历元素:for+hens[i]
2.数组的使用:
1.动态初始化:
1.1 声明数组和分配内存空间
数据类型[ ] 数组名 = new 数据类型[大小];
eg:int[ ] a = new int[5];
1.2 先声明数组 int[ ] a;
后分配内存空间a = new int[5];
仅声明数组,a = null
2.静态初始化
数据类型[ ] 数组名 = {元素1,元素2,元素3,元素4,元素5…};
eg: double[ ] hens = {3,5,1,3.4,2,50};
3.数组使用注意事项和细节:
1) 数组是多个相同类型(或自动转换)数据的组合,实现对这些数据的统一管理
2) 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用。
3) 数组创建后,如果没有赋值,有默认值
int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null
4) 使用数组的步骤 1. 声明数组并开辟空间 2.给数组各个元素赋值 3.使用数组
5) 数组的从下标是从 0 开始的。
6) 数组下标必须在指定范围内使用,否则报:下标越界异常,比如
int [] arr=new int[5]; 则有效下标为 0-4
7) 数组属引用类型,数组型数据是对象(object)
4.数组应用案例:
1) 创建一个 char 类型的 26 个元素的数组,分别 放置’A’-‘Z’。使用 for 循环访问所有元素并打印出来。
提示:char 类型
数据运算 ‘A’+1 =’B’ ArrayExercise01.java
2) 请求出一个数组 int[]的最大值 {4,-1,9, 10,23},并得到对应的下标。 ArrayExercise02.java
思路:
老韩思路分析
- 定义一个 int 数组 int[] arr = {4,-1,9, 10,23};
- 假定 max = arr[0] 是最大值 , maxIndex=0;
- 从下标 1 开始遍历 arr, 如果 max < 当前元素,说明max不是真正的 最大值, 我们就交换max=当前元素; maxIndex=当前元素下标
- 当我们遍历这个数组 arr 后 , max 就是真正的最大值,maxIndex 最大值 对应的下标
总结:
char[ ] chars = new char[26]
chars==数组类型
chars[i]==基本数据类型
char类型字符关系== ‘A’+1 =’B’
5.数组赋值机制
1) 基本数据类型赋值,这个值就是具体的数据,而且相互不影响。——>值传递
int n1 = 2;
int n2 = n1;
n2 = 80;
n1 还是=2
2) 数组在默认情况下是引用传递,赋的值是地址。——>引用传递
看一个案例,并分析数组赋值的内存图(重点, 难点. )。
//代码 ArrayAssign.java
int[] arr1 = {1,2,3};
int[] arr2 = arr1;
arr2[0] = 10
实际:arr1 = {10,2,3};
中心规则:基本类型是值传递,引用类型是地址传递
不管是基本数据类型还是引用类型,我们都拷贝一个值,
但是基本数据类型拷贝的是具体数据,引用类型拷贝的是地址
6.数组拷贝
编写代码 实现数组拷贝(内容复制)ArrayCopy.java
将 int[] arr1 = {10,20,30}; 拷贝到 arr2 数组, 要求数据空间是独立的.
int[] arr2 = new int[arr1.length]; for(int i = 0; i < arr1.length; i++) { arr2[i] = arr1[i]; }
7.数组反转
1.要求:把数组的元素内容反转。ArrayReverse.java
arr {11,22,33,44,55,66}, {66, 55,44,33,22,11}
简单概括:
方式 1:通过找规律反转-头尾交换
【思路分析】ArrayReverse.java
- 把 arr[0] 和 arr[5] 进行交换 {66,22,33,44,55,11}
- 把 arr[1] 和 arr[4] 进行交换 {66,55,33,44,22,11}
- 把 arr[2] 和 arr[3] 进行交换 {66,55,44,33,22,11}
- 一共要交换 3 次 = arr.length / 2
每次交换时,对应的下标 是 arr[i] 和 arr[arr.length - 1 -i]
方式 2:使用逆序赋值方式-逆序赋值
【思路分析, 学员自己完成】 ArrayReverse02.java
先创建一个新的数组 arr2 ,大小 arr.length
- 逆序遍历 arr ,将 每个元素拷贝到 arr2 的元素中(顺序拷贝)
- 建议增加一个循环变量 j -> 0 -> 5
- 当 for 循环结束,arr2 就是一个逆序的数组 {66, 55, 44,33, 22, 11}
- 让 arr 指向 arr2 数据空间, 此时 arr 原来的数据空间就没有变量引用
8.数组添加/扩容
课堂练习:
要求:
实现动态的给数组添加元素效果,实现对数组扩容。ArrayAdd.java
1) 原始数组使用静态分配 int[] arr = {1,2,3}
2) 增加的元素 4,直接放在数组的最后 arr = {1,2,3,4}
3) 用户可以通过如下方法来决定是否继续添加,添加成功,是否继续?y/n ArrayAdd02.java
思路分析
- 定义初始数组 int[] arr = {1,2,3}//下标 0-2
- 定义一个新的数组 int[] arrNew = new int[arr.length+1];
- 遍历 arr 数组,依次将 arr 的元素拷贝到 arrNew 数组
- 将 4 赋给 arrNew[arrNew.length - 1] = 4;把 4 赋给 arrNew 最后一个元素
- 让 arr 指向 arrNew ; arr = arrNew; 那么 原来 arr 数组就被销毁
- 创建一个 Scanner 可以接受用户输入
- 因为用户什么时候退出,不确定,老师使用 do-while + break来控制 (集合的概念)
以下代码也是集合添加元素的大致原理:
//之所以可以不断添加,
//是因为每次循环开始重新定义了arr1(相当于新数组)
//最后把新数组赋值给arr(旧数组)
int[] arr = {1,2,3};
do{
int[] arr1 = new int[arr.length + 1];
for(int i = 0;i < arr1.length - 1;i++){
arr1[i] = arr[i];
}
System.out.println("请输入添加的元素");
int addNum = myScanner.nextInt();
arr1[arr1.length - 1] = addNum;
arr = arr1;
System.out.println("====arr===========");
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
System.out.println("是否还要继续添加(y/n)");
char c = myScanner.next().charAt(0);
if(c == 'n'){
break;
}
}while(true);
课后练习题:
ArrayReduce.java
有一个数组 {1, 2, 3, 4, 5}, 可以将该数组进行缩减,提示用户是否继续缩减,每次缩减最后那个元素。当只剩
下最后一个元素,提示,不能再缩减。
9.排序的介绍
排序是将多个数据,依指定的顺序进行排列的过程。
排序的分类: 内部排序、外部排序。
简单点:内存中排序、外部排序
1.内部排序:
指将需要处理的所有数据都加载到内部存储器中(内存中)进行排序。
包括(交换式排序法、选择
式排序法和插入式排序法);
2.外部排序法:
数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括(合并排序法和直接合并排序法)。
10.冒泡排序法
冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从后向前(从下标较大的元素开始),依次比较相邻元素 的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。
11. 冒泡排序法原理
冒泡排序法案例:
BubbleSort.java
下面我们举一个具体的案例来说明冒泡法。我们将五个无序:24,69,80,57,13
使用冒泡排序法将其排成一个从小到大的有
序数列。
思路->走代码:
思路->走代码, 你可以自己完整的分析冒泡的执行流程,并可以不看老师代码,也可以写出代码.
12.查找
介绍:
在 java 中,我们常用的查找有两种:
1) 顺序查找 SeqSearch.java
2) 二分查找【二分法,我们放在算法讲解】
案例演示:
1) 有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王猜数游戏:从键盘中任意输入一个名称,判断数列中是否
包含此名称【顺序查找】 要求: 如果找到了,就提示找到,并给出下标值。
2) 请对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234} ,输入一个数看看该数组是否存在此数,并且求出下标,
如果没有就提示”没有这个数”。
顺序查找-无序就行——效率低
二分查找-数组有序——效率高
数组查找两大编程思想(重点):
判断是否找到=①boolean flag ②int index = -1 配合 break ③单个计数 ④两个计数
13.多维数组-二维数组
多维数组我们只介绍二维数组。
二维数组的应用场景
比如我们开发一个五子棋游戏,棋盘就是需要二维数组来表示。如图:
14.二维数组的使用
快速入门案例:
TwoDimensionalArray01.java
请用二维数组输出如下图形
0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 3 0 0
0 0 0 0 0 0
使用方式 1: 动态初始化
1) 二维数组定义
- 动态初始化
类型[ ][ ] 数组名=new 类型[大小][大小]
比如: int a[ ][ ]=new int[2][3]
2.静态初始化
比如: int a[ ][ ]= {{0,0,0,0,0,0},{0,0,0,0,0,0}
2) 二维数组解读:
二维数组的每个元素是一维数组
一维数组的的元素才是真正元素
访问第(i + 1)个一维数组的(j+1)个值,arr[i][j];
使用方式 2: 动态初始化
先声明:类型 数组名[][]; TwoDimensionalArray02.java
再定义(开辟空间):数组名 = new 类型[大小][大小]
有默认值:比如 int 类型的就是 0
使用方式 3: 动态初始化-列数不确定
如果没有开辟空间就是null
arr[i] = new int[i + 1];
//创建二维数组,一个有3个一维数组,但是每个一维数组还没有开数据空间
int[][] arr = new int[3][];
for(int i = 0; i < arr.length; i++) {//遍历 arr 每个一维数组
//给每个一维数组开空间 new
//如果没有给一维数组 new ,那么 arr[i]就是 null
arr[i] = new int[i + 1];
//遍历一维数组,并给一维数组的每个元素赋值
for(int j = 0; j < arr[i].length; j++) {
arr[i][j] = i + 1;//赋值
}
}
使用方式 4: 静态初始化
TwoDimensionalArray04.java
定义:类型 数组名[][] = {{值 1,值 2..},{值 1,值 2..},{值 1,值 2..}}
使用即可 [固定方式访问]
比如:
int[][] arr = {{1,1,1}, {8,8,9}, {100}};
解读:
int arr[][]={{4,6},{1,4,5,7},{-2}}; 遍历该二维数组,并得到和 TwoDimensionalArray05.java
- 使用二维数组打印一个 10 行杨辉三角 YangHui.java
总结:
|| 多个值或满足一个条件
&& 一个值或满足多个条件
|| 相反的是 !&&
int[] arr = {1,2,3,4,5};
for (int i = 0; i < arr.length; i++) {
if(i == 0 || i == 1){
System.out.println(arr[i]);//1,2
}else{
System.out.println(arr[i]);//3,4,5
}
}
16.二维数组使用细节和注意事项
1) 一维数组的声明方式有:
int[] x 或者 int x[]
2) 二维数组的声明方式有:
int[][] y 或者 int[] y[] 者 或者 int y[][]
3) 二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不相同。
比如: map[][] 是
一个二维数组
,int map [][] = {{1,2},{3,4,5}}
由 map[0] 是一个含有两个元素的一维数组 ,map[1] 是一个含有三个元素的一维数组构成,我们也称为列数不等
的二维数组
17.二维数组练习
18.本章作业
第四题:if双指针,if大小