1. 什么是数组?
-
在我们之前学习的过程中,数据类型分为:基本数据类型和引用数据类型,其中数组就属于引用数据类型。
-
在学习数组之前?我们怎么存储数据 ? 数组的出现,是为了程序设计中,处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式,这些有序排列的同类数据元素的集合称为数组。
-
数组定义
- 用来存储 固定个数,相同类型 的数据的容器.
- 数组里存储的数据叫做 元素
- 存入数组中的元素是 有顺序的。
-
如生活中的例子, 例如: 球类的集合-----足球,篮球,羽毛球等; 电器集合----电视机,洗衣机,电风扇等;把相同元素放在同一个容器中。
1.1 数组结构
-
数据结构: 数据名称,元素,下标(索引)。
- 数组名称: 用于区分不同数组,相当于变量名称。
- 元素: 数组中存储的 相同元素 的数据。
- 下标(索引):数组中元数的编号,从“0”开始,访问元素通过 下标(索引) 来访问。
-
可以把数组理解为: 像一个“羊肉串” 一样将一组 相同类型 的 “变量” 穿在一起。
- 注意, 当羊肉串的长度不能满足元素个数时,就会出现数组越界。
ArrayIndexOutOfBoundsException
- 注意, 当羊肉串的长度不能满足元素个数时,就会出现数组越界。
1.2 语法定义
-
根据场景不同,声明数组有两种不同的方式:
1.静态初始化:有2种定义格式 数据类型[] 数组名称 = {元素0,元素1,元素2,元素3} 数据类型[] 数组名称= new 数据类型[]{元素0,元素1,元素2,元素3} 2. 动态初始化:只有1种 数据类型[] 数据名称 = new 数据类型[元素个数];// 元数个数:length 即长度 数据名称[0]=元素0; ...
-
语法使用:
- 静态初始化,当我们事前知道,需要存储哪些数据时候。
public static void main(String[] args) { //1. 静态初始化,简化格式 // 数据类型[] 数组名 = {元素0,元数1,元数2} int[] array01 = {1,2,3,4,5}; //2. 静态初始化,完整格式 int[] array02 =new int[]{1,2,3,4,5}; }
- 动态初始化,当我们实现不知道,需要存储哪些数据时候。
public static void main(String[] args) { //数据类型[] 数组名 = new 数据类型[length] //length 长度 存2个元素 String[] array = new String[2]; // 增加数据 array[0] = "我"; array[1] = "是"; array[2]="谁"; //ArrayIndexOutOfBoundsException }
-
错误的写法, 静态和动态不能结合写。
String[] a = new String[5]{1,2,3,4,5};
-
数组是引用数据类型,数组的长度用 length属性 表示,长度一旦创建是不可改变的,可以允许为0。
- a.
int[] array = new int[0];//(但是没有意义)
- a.
1.3 数组创建过程分析
-
首先,定义数组的时候,分为以下几个过程:
- 数组声明:
int[] a; 声明一个整数类型数组; 会在 栈空间 中存放一个变量 a;相当于int[] a=null;
声明数组,只是给了元素类型 和 数组名称,并不能使用数组,如果想使用就需要分配空间。
- 分配空间:
a=new int[3]; 会在堆内存中开辟了3个元素的空间,堆内存中的数组地址值指向a或者是保存堆中的地址值。
使用new关键字分配空间时,必须指定元素类型和 数组元素个数,即长度length。
- 赋值:
a[0]=100; a[1]=30,元素是有下标的,通过下标去访问。如果不赋值整数int类型默认为 0;
- 数组声明:
-
声明数组和存储元素:
public static void main(String[] args) { String[] str =null; //声明阶段 str = new String[5]; // new 分配空间 // 如果没有赋值,String[] str = new String[5]; // str[0]值是默认为null ,则整数类型为0; str[0] ="h"; //跟据下标,索引赋值从0开始 str[1] ="e"; str[2] ="l"; str[3] ="l"; str[4] ="o"; // 可以指向堆中对象 String[] temp=null; temp=str; }
-
遍历数组: 即输出数组中的元素:
public class Demo03 { public static void main(String[] args) { int[] arr = new int[2]; //length 长度为2 //添加元素 arr[0]=10; arr[1]=20; //TODO 如果不便了数组怎么求和? // arr[0]+arr[1].... 一直加,很麻烦。 //1.需要通过for循环遍历数组 for (int i = 0; i <arr.length; i++) { // System.out.println(i);//输出i值:0和1 System.out.println(arr[i]); } // 2. 错误写法 为什么? // for (int i = 0; i <=arr.length; i++) {} //3.需要通过for循环遍历数组 for (int i = 0; i <=arr.length-1; i++) { // System.out.println(i);//输出i值:0和1 System.out.println(arr[i]); } } }
-
简单的理解:
- 栈:保存基本数据类型值变量,还有 ,类的实例 或对象的引用(堆中对象的引用)。
- 堆:动态产生的数据, 可以理解成: 关键字 new 出来的对象。
Class oop = new Class(); oop 是类的实例 , new Class(); 是对象。 这个oop 就是在栈中,对象在堆中,是通过实例指针操作对象,多个实例可以指向同一个对象(同上数组指向)。 基本类型的包装类是类,是存放在堆中。
1.4 入门:数组的使用
- 数组的创建,存储元素,查看数组长度,遍历元素输出。
/** * @author 吴琼 * 目的: 数组的入门练习 */ public static void main(String[] args) { // 简化版 数据类型[] 数组名 = {元素0,元素1,元素2,元素3,..} String[] name = {"周", "杰", "伦"}; // 完成版 数据类型[] 数组名 = new 数据类型[]{元素0,元素1,元素2,元素3,..} String[] name2 = new String[]{"周", "杰", "伦"}; // 动态创建 数据类型[] 数组名 = new 数据类型[长度]; 长度 = length String[] name3 = new String[3]; //开辟3个空间 String 类型默认为null; name3[0] = "周"; name3[1] = "杰"; name3[2] = "伦"; //查看数组长度 System.out.println("数组的长度:" + name.length); /* name3[3] = "!"; // 超过空间就会报异常 数组角标越界 System.out.println(name3[3]); //ArrayIndexOutOfBoundsException */ // 输出的是地址值?为什么不同? System.out.println("name的地址值:" + name); // [Ljava.lang.String;@28d93b30 System.out.println("name2的地址值:" + name2); // Ljava.lang.String;@1b6d3586 System.out.println("name3的地址值:" + name3); // [Ljava.lang.String;@4554617c // 引用类型发生的地址值引用! String[] name4 = null; name4 = name; // 为什么和 name 地址值相同! System.out.println("name4的地址值:" + name4); // [Ljava.lang.String;@28d93b30 // 二, 单纯输出数组显示结果,不使用, 用Arrays.toString(数组名); 工具类的对象 System.out.println("显示name数组结果:" + Arrays.toString(name)); // 三, 遍历输出数组值 即循环输出 for (int i = 0; i < name.length; i++) { System.out.println("name数组中的值是:" + name[i]); } // 写法2 数组0 开始 如果i<=name2.length 数组就会越界 写成i<=name2.length-1 for (int i = 0; i <= name2.length - 1; i++) { System.out.println("name2数组的值是:" + name2[i]); } }
-
输出结果:
数组的长度:3 name的地址值:[Ljava.lang.String;@28d93b30 name2的地址值:[Ljava.lang.String;@1b6d3586 name3的地址值:[Ljava.lang.String;@4554617c name4的地址值:[Ljava.lang.String;@28d93b30 显示name数组结果:[周, 杰, 伦] name数组中的值是:周 name数组中的值是:杰 name数组中的值是:伦 name2数组的值是:周 name2数组的值是:杰 name2数组的值是:伦
- 简单理解 ,引用传递 :
int[] a = new int[2]; int[] b = {1,2,6,4,5}; a=b;//这条语句将导致a的引用发生变化,a也成为对b所引用的数组的引用。 //结果是: [1, 2, 6, 4, 5] System.out.println(Arrays.toString(a));
2. 课堂案例
2.1. 输入元素打印该元素索引
- 通过数组中元素,查找打印该元素的索引。
public static void main(String[] args) { //1. 创建数组,添加元素 String[] arr = new String[3]; arr[0]="你"; arr[1]="是"; arr[2]="谁"; //2. 输入查找元素 System.out.println("请输入要查找的元素: "); String s = new Scanner(System.in).next(); //3.遍历数组, if判断 for (int i = 0; i <=arr.length-1 ; i++) { if (arr[i].equals(s)){ // 为什么不使用 ==,而使用equals()? System.out.println("该元素的下标为 "+i); } } }
-
输出结果:
请输入要查找的元素: 你 该元素的下标为 0
2.2. 控制台接收,四科成绩求平均分
- 控制台接收输入的张三的4科成绩,并计算平均值!
- 要求使用数组 进行存储。
/**
* @Author wq
* 用数组存储成绩,计算4门功课,并求平均值!
*/
public class AvgDemo {
public static void main(String[] args) {
double sum=0; // 3.1 求和
// 1.定义长度为4的数组存储成绩
double[] score = new double[4];
// 2.遍历数组 输入成绩
for (int i=0; i<=score.length-1;i++){
System.out.println("请输入第"+(i+1)+"科成绩:");
score[i]= new Scanner(System.in).nextDouble();
// 2.1 可以做一个验证,正数就求和。
if (score[i]>=0) {
//3.求和
sum += score[i];
}else{
System.out.println("输入有误,从新输入");
break;
}
}
// 4计算求和
System.out.println("4门成绩的平均值是: "+sum/score.length);
// 5.输出成绩 工具类 Arrays.toString();
System.out.println("各科成绩:"+ Arrays.toString(score));
}
}
2.3. 比较数组中,最大值,最小值
- 在不知道要定义数组长度的情况下,控制台接收数组元数个数,比较元数最大值和最小值。
- 提示:在不知道长度情况下,根据输入长度来确定数组长度。
/**
* @Author wq
*/
public class ArrayDemo3 {
public static void main(String[] args) {
System.out.println("请输入数组比较的数量:");
int num = new Scanner(System.in).nextInt();
//1.在不确定存储的元素的情况下,这样节省空间
double[] price = new double[num];
//2.操作数组就用循环,遍历输入数组元数。
for (int i=0;i<=price.length-1;i++){
System.out.println("请输入第"+(i+1)+"个数:");
// 循环输入
price[i]= new Scanner(System.in).nextDouble();
}
// 输出输入商品价格
System.out.println("输出元素: "+Arrays.toString(price));
//3.求最大值. ? 假设如果,比较出最小值呢?
double max = price[0]; // 假设你的最大值是第一个(第几个都行)
for (int i=0;i<price.length;i++){
if (max<price[i]){
max=price[i];
}
}
System.out.println("最大值是: "+max);
}
}
-
输出结果:
请输入数组比较的数量: 4 请输入第1个数: 2.1 请输入第2个数: 36.8 请输入第3个数: 19.5 请输入第4个数: 45.9 输出元素: [2.1, 36.8, 19.5, 45.9] 最大值是: 45.9
- 思考 : 要是 求数组的最小值怎么搞?
2.4. 数组算法
2.4.1 数组后移(一)
- 要求:将数组中的元数整体向后移动一位。该怎么做?
- 数组一旦定义长度,就无法改变,那怎么后移 ?
- 提示:先搞明白一件事,从前面开始往后移动?还是从后面开始往后移动?
- 代码如下:
/** * [18,22,33,55,2,6] * 移动完之后! * [18,18,22,33,55,2] */ public class ArrayDemo4{ public static void main(String[] args) { // 声明一个数组 int[] num = new int[]{18,22,33,55,2,6}; for (int i = num.length-1;i>0;i--){ // 向后移动一位,从后面开始移动 num[i] =num[i-1]; //推理图 } System.out.println("数组移动之后为: "+Arrays.toString(num)); } }
-
输出结果:
数组移动之后为: [18, 18, 22, 33, 55, 2]
2.4.2 数组任意插入(二)
-
接 2.4 数组后移(一) 案例数组后移,假设我要在任意位置插入一个元素怎么处理?
- 一定要接着案例 2.4 数组后移(一) 接着思考。
- 提示: 关键点,移动几次。
public static void main(String[] args) { int[] num = new int[]{18,22,33,55,2,6}; System.out.println("请输入要插入的元素"); int word = new Scanner(System.in).nextInt(); System.out.println("请输入要插入的索引"); //2 移动次数 int index = new Scanner(System.in).nextInt(); for (int i = num.length-1; i>index ; i--) { num[i]=num[i-1]; System.out.println(i); } // 3 插入数组 num[index]=word; System.out.println(Arrays.toString(num)); }
3. Arrays 类中的方法
3.1 Arrays.toString(Object[] array);
- 返回值 String类型 ,返回数组的 字符串形式。
/**
* @Author wq
*/
public class ArraysTools {
public static void main(String[] args) {
/*Arrays.toString(Object[] array),返回String类型可以直接输出*/
String[] name = {"张楚岚","宝儿姐","徐三","徐四"};
int[] age =new int[]{18,19,20,21};
System.out.println(Arrays.toString(name));
System.out.println(Arrays.toString(age));
}
}
-
输出结果:
[张楚岚, 宝儿姐, 徐三, 徐四] [18, 19, 20, 21]
3.2 Arrays.sort (Object[] array)
- void 无返回值 , 对数组按照 升序排序, 整数类型,浮点型,字符型。
public class ArraysTools2 {
public static void main(String[] args) {
char[] chars = {'e','d','c','a'};
int[] age =new int[]{18,19,20,21};
/* 升序排序,void 无法直接输出*/
Arrays.sort(chars);
Arrays.sort(age);
//排序后输出
System.out.println(Arrays.toString(chars));
System.out.println(Arrays.toString(age));
}
}
-
输出结果:
[a, c, d, e] [18, 19, 20, 21]
3.3 Arrays.sort(Object[] array,int fromIndex ,int toIndex)
- 对数组元素指定范围进行排序,从formindex索引,开始 到 toindex-1 索引,范围内进行排序。
public class ArraysTools2 {
public static void main(String[] args) {
int[] age =new int[]{8,7,6,5,4,3,2,1,0};
/*相当于从6开始 到 4 结束 */
Arrays.sort(age,2,5); // toindex 相当于到下标为(5-1) 4
//排序后输出
System.out.println(Arrays.toString(age));
}
}
-
输出结果:
[8, 7, 4, 5, 6, 3, 2, 1, 0]
3.4 Arrays.equals(name,Object[] a,Object[] a2)
- 比较两个数组的内容是否相等,
public class ArraysTools3 {
public static void main(String[] args) {
String[] name = {"张楚岚","宝儿姐","徐三","徐四"};
String[] name2 =new String[] {"张楚岚","宝儿姐","徐三","徐四"};
System.out.println(Arrays.equals(name,name2)); // 主要比较的是内容是否相等
}
}
- 输出结果:
true
3.5 Arrays.copyOf(Objetc[] original,newLength)
- 复制数组成为一个新数组,Objetc[] original原数组, newLength是要复制原数组的长度。
public class ArraysTools4 {
public static void main(String[] args) {
/*复制一个数组*/
int[] num ={18,19,20,21,22};
System.out.println(Arrays.toString(Arrays.copyOf(num,num.length)));
String[] name = {"张楚岚","宝儿姐","徐三","徐四"};
String[] newArrays = Arrays.copyOf(name, 3);// 有返回值 返回相应类型的数组
System.out.println(Arrays.toString(newArrays));
}
}
输出结果:
[张楚岚, 宝儿姐, 徐三]
[18, 19, 20, 21, 22]
4. 冒泡排序
4.1 什么是冒泡?
- 基本思想:是对比相邻的元数值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(相互交换连个元素的位置,从大到小,从A到Z),这样较小的元素就像气泡一样从底部上升到顶部。
- 可以 实现升序或者降序。
- 图片来源于网络,如有侵权可删除。
4.2 代码实现
public class BubbleSort {
public static void main(String[] args) {
/*可以实现数组的升序或者降序*/
int[] num = new int[]{89,88,87,30};
BubbleSort.bubbleSort(num);
System.out.println("冒泡的结果:"+Arrays.toString(num));
}
/**
*
* @param arr
*/
public static void bubbleSort(int[] arr){
for (int i=1;i<arr.length;i++){ // 循环比较次数为length-1次
//比较相邻的两个元素,大的“冒泡”
for (int j=0;j<arr.length-i;j++){ // for (int j=0;j<arr.length-1;j++)?? 为什么-1也行!
// core 代码 升序 比较+交换位置
if (arr[j]>arr[j+1]){
// 将比较的两个值进行交换
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
// System.out.println(Arrays.toString(arr));
}
}
}
输出结果:
[88, 87, 30, 89]
[87, 30, 88, 89]
[30, 87, 88, 89]
冒泡的结果:[30, 87, 88, 89]
4.3 原理分析
- 分析图如下:
- 如有有n个元素, 就循环n-1次。
- 外循环控制 循环比较次数,内循环控制 相邻元素比较和交换位置,如果比较不对,就不需要换。
for (int j=0;j<arr.length-i;j++) 为什么要-i 因为每次循环一次都会选出一个最大值,这样内循环不用每次都循环完,就根据 i 值变化。如上图。
- 每次循环的结果都会确定一个最大值。这样每次循环可以减少一次。
for (int j=0;j<arr.length-1;j++); 效率低每次都循环N-1次
4.4 冒泡降序怎么实现
- 思考 :
如果做降序排序怎么搞??
在这里插入代码片