文章目录
PPT链接:点击这里
1、 数组的概述
1、数组的理解
- 数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理
2、数组的相关概念
- 数组名、元素、角标、下标、索引
- 数组的长度:元素的个数
3、数组的特点
- 数组本身是引用数据类型。数组中的元素既可以是基本数据类型也可以是引用数据类型
- 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址
- 数组的长度一旦确定,就不能修改
- 数组是有序排列的
4、数组的分类
-
① 按照维数:一维数组、二维数组、三维数组……
-
② 按照数组元素类型:基本数据类型元素的数组、引用类型元素的数组
2、 一维数组的使用
数组元素的默认初始化值
- 数组元素是整形:
0
- 数组元素是浮点型:
0.0
- 数组元素是char型:
0
或'\u0000'
,而非'0'
- 数组元素是boolean型:
false
- 数组元素是引用数据类型:
null
数组是引用数据类型,赋值时用new,声明数组:int[] arr 可以将 int[] 看做数据类型更容易理解
public class ArrayTest {
public static void main(String[] args) {
int num; //声明
num = 10; //初始化
int id = 1001; //声明 + 初始化
//********************1.一维数组的声明和初始化**********
int[] ids; //声明
//1.1 静态初始化:数组的初始化和数组元素的赋值操作同时进行
ids = new int[]{1001,1002,1003,1004};
//1.2 动态初始化:数组的初始化和数组元素的赋值操作分开进行
String[] names = new String[5];
//也是正确的写法:
int[] arr7 = {1,2,3,5,4};//类型推断
//总结:数组一旦初始化完成,其长度就确定了
//********************2.如何调用数组的指定位置的元素******
//通过角标的方式调用,数组的角标(或索引)从0开始的,到数组的长度-1结束
names[0] = "王铭";
names[1] = "王赫";
names[2] = "张学良";
names[3] = "孙居龙";
names[4] = "王宏志"; //charAt(0)获取“王”
// names[5] = "周扬"; //如果数组超过角标会通过编译,运行失败
System.out.println(names[4].charAt(0));//王
//********************3.如何获取数组的长度***************
//属性:length
System.out.println(names.length); //5
System.out.println(ids.length); //4
//********************4.如何遍历数组********************
for(int i = 0;i < names.length;i++){
System.out.println(names[i]);
}
}
}
public class ArrayTest {
public static void main(String[] args) {
//整形:0
int[] arr = new int[4];
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
//浮点型:0.0
float[] arr2 = new float[5];
for(int i = 0;i < arr2.length;i++){
System.out.println(arr2[i]);
}
//字符型:0或'\u0000',而非'0'
char[] arr3 = new char[5];
for(int i = 0;i < arr3.length;i++){
System.out.println("----" + arr3[i] + "****");//---- ****
}
//验证
if(arr3[0] == 0){
System.out.println("你好!");
}
//布尔型:false
boolean[] arr4 = new boolean[5];
for(int i = 0;i < arr2.length;i++){
System.out.println(arr4[i]);
}
//引用数据类型:null
String[] arr5 = new String[5];
for(int i = 0;i < arr2.length;i++){
System.out.println(arr5[i]);
}
//验证
if(arr5[0] == null){
System.out.println("北京欢迎你!");
}
}
}
2.1、内存的简化结构
2.2、一维数组的内存解析
【案例1】
int[] arr = new int[]{1,2,3};
String[] arr1 = new String[4];
arr1[1] = “刘德华”;
arr1[2] = “张学友”;
arr1 = new String[3];
System.out.println(arr1[1]);//null
【案例2】
当堆中的数组没有栈中的变量指过来时(例如:方法执行完,变量全部出栈),这时就没有指针指向堆中new出来的空间,一段时间后该空间就会被当成垃圾回收
2.3、练习
从键盘读入学生成绩,找出最高分,并输出学生成绩等级
成绩>=最高分-10 等级为’A’
成绩>=最高分-20 等级为’B’
成绩>=最高分-30 等级为’C’
其余等级为’D’
提示:先读入学生人数,根据人数创建int数组,存放学生成绩
【代码实现】
import java.util.Scanner;
public class ArrayDemo {
public static void main(String[] args) {
//1.使用Scanner读取学生的个数
Scanner scan = new Scanner(System.in);
System.out.print("请输入学生人数:");
int num = scan.nextInt();
//2.创建数组,存储学生成绩,动态初始化
int[] str = new int[num];
System.out.println("请输入" + num + "个学生成绩");
//3.给数组中的元素赋值
int maxnum = 0;
for(int i = 0;i < str.length;i++){
str[i] = scan.nextInt();//直接输入数据给数组元素
//4.获取数组元素中的最大值:最高分
if(str[i] > maxnum){
maxnum = str[i];
}
}
//5.根据每个学生成绩与最高分的差值,得到每个学生的等级,并输出等级和成绩
char level; //这里可以不用初始化,因为level一定会走 多选一 中的一个被赋值
for(int i = 0;i < str.length;i++){
if(maxnum - str[i] <= 10){
level = 'A';
}else if(maxnum - str[i] <= 20){
level = 'B';
}else if(maxnum - str[i] <= 30){
level = 'C';
}else{
level = 'D';
}
System.out.println("student " + i + "score is" + str[i] + " grade is " + level);//不会报错,level会被赋值
}
}
}
3、 多维数组的使用
如果说可以把一维数组当成几何中的线性图形,那么二维数组就相当于是一个表格,像下图Excel中的表格一样
对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。从数组底层的运行机制来看,其实没有多维数组
public class ArrayTest2 {
public static void main(String[] args) {
//********************1.二维数组的声明和初始化*************
int[] arr = new int[]{1,2,3};//一维数组
//静态初始化
int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
//动态初始化1
String[][] arr2 = new String[3][2];
//动态初始化2
String[][] arr3 = new String[3][];
//也是正确的写法:
int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};
//********************2.如何调用数组的指定位置的元素********
System.out.println(arr1[0][1]);//2
System.out.println(arr2[1][1]);//null
// System.out.println(arr3[1][0]);//会报错,出现空指针异常:java.lang.NullPointerException
arr3[1] = new String[4];
System.out.println(arr3[1][0]);//null
//********************3.获取数组的长度********************
System.out.println(arr4.length);//3
System.out.println(arr4[0].length);//3
System.out.println(arr4[1].length);//4
//********************4.如何遍历二维数组******************
for(int i = 0;i < arr4.length;i++){
for(int j = 0;j < arr4[i].length;j++){
System.out.print(arr4[i][j] + " ");
}
System.out.println();
}
}
}
规定: 二维数组分为外层数组的元素,内层数组的元素
int[][] arr = new int[4][3];
外层元素:arr[0],arr[1]等------------行
内层元素:arr[0][0],arr[1][2]等------列
数组元素的默认初始化值
- 针对于初始化方式1:比如:
int[][] arr = new int[4][3];
- 外层元素的初始化值为:地址值
- 内层元素的初始化值为:与一维数组初始化情况相同
- 针对于初始化方式2:比如:
int[][] arr = new int[4][];
- 外层元素的初始化值为:null
- 内层元素的初始化值为:不能调用,否则报错
public class ArrayTest3 {
public static void main(String[] args) {
int[][] arr = new int[4][3];
System.out.println(arr[0]);//[I@15db9742
System.out.println(arr[0][0]);//0
System.out.println(arr);//[[I@6d06d69c
float[][] arr1 = new float[4][3];
System.out.println(arr1[0]);//地址值:[F@7852e922
System.out.println(arr1[0][0]);//0.0
String[][] arr2 = new String[4][2];
System.out.println(arr2[1]);//地址值:[Ljava.lang.String;@4e25154f
System.out.println(arr2[1][1]);//null
double[][] arr3 = new double[4][];
System.out.println(arr3[1]);//null
// System.out.println(arr3[1][0]);//报错,出现空指针异常:java.lang.NullPointerException
}
}
3.1、二维数组的内存解析
【案例1】
int[][] arr1 = new int[4][];
arr1[1] = new int[]{1,2,3};
arr1[2] = new int[4];
arr1[2][1] = 30;
【案例2】
int[][] arr4= new int[3][];
System.out.println(arr4[0]);//null
System.out.println(arr4[0][0]);//报错
arr4[0] = new int[3];
arr4[0][1] = 5;
arr4[1] = new int[]{1,2};
【案例3】
int[][] arr = new int[3][];
arr[1] = new int[]{1,2,3};
arr[2] = new int[3];
System.out.println(arr[0]);//null
System.out.println(arr[0][0]);//报异常
【案例4】
int[][] arr1 = new int[4][];
arr1[0] = new int[3];
arr1[1] = new int[]{1,2,3};
arr1[0][2] = 5;
arr1 = new int[2][];
3.2、练习
3.2.1、练习1
获取arr数组中所有元素的和。提示:使用for的嵌套循环即可
【代码实现】
public class ArrayExer1 {
public static void main(String[] args) {
int[][] arr = new int[][]{{3,5,8},{12,9},{7,0,6,4}};
int sum = 0;//记录总和
for(int i = 0;i < arr.length;i++){
for(int j = 0;j < arr[i].length;j++){
sum += arr[i][j];
}
}
System.out.println("总和为:" + sum);
}
}
3.2.2、练习 2(判断)
3.2.3、练习 3(杨辉三角)
使用二维数组打印一个 10 行杨辉三角。
提示:
1. 第一行有 1 个元素, 第 n 行有 n 个元素
2. 每一行的第一个元素和最后一个元素都是 1
3. 从第三行开始, 对于非第一个元素和最后一个元素的元素。即:
yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j];
【代码实现】
public class YangHuiTest {
public static void main(String[] args) {
//1.声明并初始化二维数组
int[][] yangHui = new int[10][];
//2.给数组的元素赋值 注意:每一行有多少个元素
//yangHui[0] = new int[1];
//yangHui[1] = new int[2];
for(int i = 0;i < yangHui.length;i++){
//开辟空间,初试值是0
yangHui[i] = new int[i + 1];
//2.1 给首末元素赋值
yangHui[i][0] = yangHui[i][i] = 1;
//2.2 给每行的非首末元素赋值:忽略掉第1列和最后1列
for(int j = 1;j < yangHui[i].length - 1;j++){//从第2列开始
yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j];
}
}
//3.遍历二维数组
for(int i = 0;i < yangHui.length;i++){
for(int j = 0;j < yangHui[i].length;j++){
System.out.print(yangHui[i][j] + " ");
}
System.out.println();
}
}
}
3.2.4、练习 4(面试题目)
创建一个长度为 6 的 int 型数组,要求取值为 1-30,同时元素值各不相同
【代码实现1】
public class ArrayEver1 {
public static void main(String[] args) {
int[] arr = new int[6];
for(int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random() * 30) + 1;// [0,1) [0,30) [1,31)
boolean flag = false;//flag:用于判断是否重复的标志
while(true) {
for(int j = 0; j < i; j++) {//比较 新来的数 和 前面已经赋值的数
if(arr[j] == arr[i]) {
flag = true;
break;
}
}
if(flag == true) {
arr[i] = (int) (Math.random() * 30) + 1;//有重复就重新赋值
flag = false;
continue;//因为不能保证重新赋的值是否有重复,就重新启动for循环再判断是否重复
}
break;//均没有重复就结束while循环
}
}
//遍历数组
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");//25 29 27 14 30 2
}
}
}
【代码实现2】
public class ArrayEver2 {
public static void main(String[] args) {
int[] arr2 = new int[6];
for (int i = 0; i < arr2.length; i++) {
arr2[i] = (int) (Math.random() * 30) + 1;//[0,1) [0,30) [1,31)
for (int j = 0; j < i; j++) {//比较 新来的数 和 前面已经赋值的数
if (arr2[i] == arr2[j]) {
i--; //i往前挪一位(因为最外层for循环会进行i++),让其重新赋值(下面的break会重新跳到最外层for循环)
break; //结束内层的for循环
}
}
}
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i] + " ");
}
}
}
4、 数组中涉及到的常见算法
4.1、数组的最大值、最小值、平均数、总和
定义一个 int 型的一维数组,包含 10 个元素,分别赋一些随机整数,然后求出所有元素的最大值,最小值,总和值,平均值,并输出出来
要求:所有随机数都是两位数
public class ArrayTest1 {
public static void main(String[] args) {
int[] arr = new int[10];
//数组赋值
for(int i = 0;i <arr.length;i++){
arr[i] = (int)(Math.random() * (99 - 10 + 1) + 10);//[10,99]
}
//遍历
for(int i =0;i < arr.length;i++){
System.out.print(arr[i] + " ");
}
System.out.println();
//求数组元素的最大值
int maxValue = arr[0];
for(int i = 1;i < arr.length;i++){
if(arr[i] > maxValue){
maxValue = arr[i];
}
}
System.out.println("最大值:" + maxValue);
//求数组元素的最小值
int minValue = arr[0];
for(int i = 1;i <arr.length;i++){
if(arr[i] < minValue){
minValue = arr[i];
}
}
System.out.println("最小值:" + minValue);
//求数组元素的总和
int sum = 0;
for(int i = 1;i <arr.length;i++){
sum += arr[i];
}
System.out.println("总和:" + sum);
//求数组元素的平均数
double avgVales = sum / arr.length;
System.out.println("平均数:" + avgVales);
}
}
4.2、练习
(1)创建一个名为 ArrayTest 的类,在 main()方法中声明 array1 和 array2 两个变量,他们是 int[] 类型的数组
(2)使用大括号{},把 array1 初始化为 8 个素数:2,3,5,7,11,13,17,19。
(3)显示 array1 的内容。
(4)赋值 array2 变量等于 array1,修改 array2 中的偶索引元素,使其等于索引值(如 array[0]=0,array[2]=2)。打印出 array1。
【代码实现】
public class ArrayTest {
public static void main(String[] args) {
//1.声明 array1 和 array2 两个 int[]变量
int[] array1,array2;
//2.array1 初始化
array1 = new int[]{2,3,5,7,11,13,17,19};
//3.显示 array1 的内容
for(int i = 0;i < array1.length;i++){
System.out.print(array1[i] + "\t");
}
//4.1 赋值 array2 变量等于 array1 (不能称作数组的复制)
array2 = array1;
//4.2 修改 array2 中的偶索引元素,使其等于索引值(如 array[0]=0,array[2]=2)
for(int i = 0;i < array2.length;i++){
if(i % 2 == 0){
array2[i] = i;
}
}
System.out.println();
//4.3 打印出 array1
for(int i = 0;i < array1.length;i++){
System.out.print(array1[i] + "\t");
}
}
}
思考:上述 array1 和 array2 是什么关系?
array1 和 array2 地址值相同,都指向了堆空间的唯一的一个数组实体
拓展:修改题目,实现 array2 对 array1 数组的复制
4.3、数组的复制、反转
public class ArrayTest2 {
public static void main(String[] args) {
String[] arr = new String[]{"JJ","DD","MM","BB","GG","AA"};
//数组的复制(区别于数组变量的赋值:arr1 = arr)
String[] arr1 = new String[arr.length];
for(int i = 0;i < arr1.length;i++){
arr1[i] = arr[i];
}
//数组的反转
//方法1:
for(int i = 0;i < arr.length / 2;i++){//注意:反转一半
String temp = arr[i];
arr[i] = arr[arr.length -1 - i];//理解:最后一个数的下标:length - 1
arr[arr.length -1 -i] = temp;
}
//方法2:
for(int i = 0,j = arr.length - 1; i < j; i++,j--){//第一个和最后一个
String temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
4.4、数组中的查找(搜索)
4.4.1、线性查找
public class ArrayTest3 {
public static void main(String[] args) {
String[] arr = new String[]{"AA","BB","CC","DD","EE","FF"};
String dest = "CC";//要查找的元素
boolean isFlag = false;//没有找到时要有一个判断,否则找到和没找到都会输出Sout("很遗憾,没有找到的啦!");
for(int i = 0;i < arr.length;i++){
if(dest.equals(arr[i])){
System.out.println("找到了指定的元素,位置为:" + i);
isFlag = true;
break;//如果找到就直接退出
}
}
if(isFlag == false){
System.out.println("很遗憾,没有找到的啦!");
}
}
}
引用数据类型比较两个数是否相等用equals()
,equals 表示的是比较的内容相等,如:dest.equals(arr[i])
比较 dest 和 arr[i] 的内容相等;如果是 int 类型进行比较则用dest == arr[i]
4.4.2、二分查找法
前提:所要查找的数组必须有序
注意: 循环条件要使用while(left <= right)
,因为当left == right
时,区间[left,right]
仍然有效
/* 2 5 7 8 10 15 18 20 22 25 28 20
0 1 2 3 4 5 6 7 8 9 10
low = 0 6 6 7
hig = 10 10 7 7 在[7,7]范围内仍然要继续运行,接下来就是middle=7,找到20 */
public class ArrayTest4 {
public static void main(String[] args) {
int[] arr = new int[]{-98,-34,2,34,54,66,79,105,210,333};
int dest = -34;
int left = 0;//初始的首索引
int right = arr.length - 1;//初始的末索引
boolean isFlag = false;
while(left <= right){//注意=
int middle = (left + right) / 2;
if(dest == arr[middle]){
System.out.println("找到了指定元素,位置为:" + middle);
isFlag = true;
break;
}else if(arr[middle] > dest){
right = middle - 1;
}else{ //arr[middle] < dest
left = middle + 1;
}
}
if(isFlag == false){
System.out.println("很遗憾,没找到!");
}
}
}
4.5、冒泡排序
冒泡排序的原理非常简单,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来
排序思想
- 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数
- 针对所有的元素重复以上的步骤,除了最后一个
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止
public class BubbleSortTest {
public static void main(String[] args) {
int[] arr = new int[]{43,32,76,92,-65,85,71,-42};
for(int i = 0;i < arr.length - 1;i++){ //一共比较arr.length - 1轮,最后剩下最小的一个,不必比较
for(int j = 0;j < arr.length - 1 - i;j++){ //每一轮比较几次
if(arr[j] > arr[j+1]){ //j是从0开始的
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
//遍历
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");
}
}
}
5、 Arrays 工具类的使用
java.util.Arrays
类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法
工具类都是一些静态方法,可以通过类直接调用
import java.util.Arrays;
public class ArraysTest {
public static void main(String[] args) {
//1.boolean equals(int[] a,int[] b):判断两个数组是否相等
int[] arr1 = new int[]{1,2,3,4};
int[] arr2 = new int[]{1,3,2,4};
boolean isEquals = Arrays.equals(arr1, arr2);
System.out.println(isEquals);
//2.String toString(int[] a):输出数组信息
System.out.println(Arrays.toString(arr1));
//3.void fill(int[] a,int val):将指定值填充到数组之中
Arrays.fill(arr1,10);
System.out.println(Arrays.toString(arr1));
//4.void sort(int[] a):对数组进行排序
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));
//5.int binarySearch(int[] a,int key):对排序后的数组进行二分法检索指定的值
int[] arr3 = new int[]{-98,-34,2,34,54,66,79,105,210,333};
int index = Arrays.binarySearch(arr3, 210);
if(index >= 0){
System.out.println(index);
}else{
System.out.println("未找到");
}
}
}
6、 数组使用中的常见异常
1、数组角标越界的异常:ArrayIndexOutOfBoundsException
2、空指针异常:NullPointerException
public class ArrayExceptionTest {
public static void main(String[] args) {
//1.数组角标越界的异常:ArrayIndexOutOfBoundsException
int[] arr = new int[]{1,2,3,4,5};
//错误1:右越界
for(int i = 0;i <= arr.length;i++){
System.out.println(arr[i]);
}
//错误2:左越界
System.out.println(arr[-2]);
//2.空指针异常:NullPointerException
//情况1:
int[] arr2= new int[]{1,2,3};
arr2 = null;
System.out.println(arr2[0]);
//情况2:
int[][] arr2 = new int[4][];
System.out.println(arr2[0][0]);
//情况3:
String[] arr3 = new String[]{"AA","BB","CC"};
arr3[0] = null;
System.out.println(arr3[0].toString());
}
}
物竞天择,适者生存,加油吧 !!!