day04_数组

数组

学习目标:

1. jvm内存图入门
2. 一维数组的使用
3. 二维数组的使用
4. 数组的内存结构
5. 数组中常见算法
6. 数组中常见的异常

视频教程:https://www.bilibili.com/video/BV1rB4y1Y769?p=1

一、JVM内存图入门

java程序运行在jvm上,jvm内存主要分为五块,结构如下:

在这里插入图片描述

每块内存负责的职责如下:

  1. Java虚拟机栈(Java Virtual Machine Stacks):描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame),栈帧中存储着局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,会对应一个栈帧在虚拟机栈中入栈到出栈的过程。与程序计数器一样,Java虚拟机栈也是线程私有的。

    局部变量和引用地址都是在栈内存中。

  2. 堆:此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。

  3. 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区存放的数据只有一份

  4. 本地方法栈(Native Method Stack):与Java虚拟机栈作用很相似,它们的区别在于虚拟机栈为虚拟机执行Java方法(即字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。例如调用本地c/c++的方法。

  5. 程序计数器:程序计数器是记录当前线程所执行的指令行数。

二、数组的概述

2.1 为什么需要数组

为什么要有数组?在开发中,我们常常需要存取很多相同类型的数据,用变量的方式需要定义很多变量,不方便管理。所以引入数组的概念,一次存取多个相同类型的数据。数组有两个一定,一个类型一定,一个是大小一定。

2.2 数组的基本概念

数组中存在着一些重要的概念,如下所示:

  • 数组名:数组的名称,数组内存的首地址
  • 下标名(索引):数组元素的序号索引,从0开始
  • 元素:数组中存放的内容
  • 长度 :数组的长度

在这里插入图片描述

三、一维数组的使用

3.1 数组的定义

一维数组的定义语法如下:

在这里插入图片描述

示例:

/**
 * 数组定义
 */
public class ArrayDemo1 {
    public static void main(String[] args) {
        //定义数组
        int[] arr1;
        String [] arr2;
    }
}

3.2 数组的初始化

数组动态初始化语法:

在这里插入图片描述

示例:

/**
 * 数组定义,以及动态初始化
 */
public class ArrayDemo1 {
    public static void main(String[] args) {
        //定义数组
        int[] arr1;
        //数组动态初始化
        arr1 = new int[4];
        arr1[0] = 10;
        arr1[1] = 20;
        arr1[2] = 30;
        arr1[3] = 40;
        //取值
        System.out.println(arr1[0]);
        System.out.println(arr1[1]);
        System.out.println(arr1[2]);
        System.out.println(arr1[3]);
    }
}

数组静态初始化语法:

在这里插入图片描述

示例:

/*
数组的定义与静态初始化
 */
public class ArrayDemo2 {
    public static void main(String[] args) {
        //数组的声明
        // String[] arr = new String[]{"乔峰","段誉","杨过"};
        //简写
        String[] arr = {"乔峰","段誉","杨过"};
        //取值
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

3.3 数组元素的引用

引用数组元素内容需要注意以下几点:

  • 定义并用运算符new为之分配空间后,才可以引用数组中的每个元素;
  • 数组元素的引用方式:数组名[数组元素下标]
  • 数组元素下标可以是整型常量或整型表达式。如a[3] , b[i] , c[6*i];
  • 数组元素下标从0开始;长度为n的数组合法下标取值范围: 0 —>n-1;如int a[]=new int[3]; 可引用的数组元素为a[0]、a[1]、a[2]
  • 每个数组都有一个属性length指明它的长度,例如:a.length 指明数组a的长 度(元素个数) 。数组一旦初始化,其长度是不可变的

示例1:数组元素的引用

/**
 * 数组元素的引用
 */
public class ArrayDemo3 {
    public static void main(String[] args) {
        //数组的定义
        int[] arr = {1,3,5,7,9};
        //查看数组的长度
        System.out.println(arr.length);
        // 查看数组内容
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
        System.out.println(arr[3]);
        System.out.println(arr[4]);
        // 数组下标超过最大下标会越界,报异常ArrayIndexOutOfBoundsException
        System.out.println(arr[5]);

    }
}

示例2:数组的循环赋值与取值

/**
 * 数组的循环赋值与取值
 */
public class ArrayDemo4 {
    public static void main(String[] args) {
        //定义数组
        int[] arr = new int[5];
        //循环赋值
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i*5;
        }
        //循环取值
        for (int i = 0; i < arr.length ; i++) {
            System.out.println(arr[i]);
        }
    }
}

3.4 数组的注意事项

数组在使用过程中需要注意以下几点:

  • 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。
  • 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址。
  • 数组的长度一旦确定,就不能修改。
  • 数组的分类:
    • 按照维度:一维数组、二维数组、三维数组、…
    • 按照元素的数据类型分:基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)

3.5 forEach的应用

forEach可以遍历数组或集合容器中的数据,语法如下:

在这里插入图片描述

示例:

/**
 * forEach遍历
 */
public class ArrayDemo5 {
    public static void main(String[] args) {
        //数组定义
        int[] arr = {1,3,5,7,9};
        //数组遍历
        for(int num : arr){
            System.out.println(num);
        }
    }
}

3.6 数组元素默认值

当数组元素没有赋值时,是存在默认值的,默认值如下:

在这里插入图片描述

3.7 一维数组内存图

在这里插入图片描述

3.8 小结

  1. 数组的基本使用
  2. 数据类型可以是基本类型或引用类型
  3. 数组类型固定长度不变
  4. 数组默认值
  5. 数组的内存图

四、一维数组练习题

4.1 数组赋值练习

将班级所有同学名字录入到一个一维数组中 。

参考答案:

/**
 * 将班级所有同学名字录入到一个一维数组中
 */
public class ArrayTest1 {
    public static void main(String[] args) {
        //1.创建大小为5的String类型数组
        String[] names = new String[5];
        //2.创建扫描仪对象
        Scanner input = new Scanner(System.in);
        for(int i=0;i<names.length;i++) {
            //3.提示信息
            System.out.println("请输入第"+(i+1)+"个同学名字");
            //4.接收客户的输入信息
            String name = input.nextLine();
            //5.将名字存入数组中
            names[i] = name;
        }
        System.out.println("学生信息如下----------");
        for(int i=0;i<names.length;i++) {
            System.out.println(names[i]);
        }
    }
}

4.2 求数组值练习

已知一个一维数组如下int[] arr = {1,3,11,5,7,9};求出所有元素的最大值,最小值,和值,平均值,并输出出来。

参考答案:

/**
 * 已知一个一维数组如下int[] arr = {1,3,11,5,7,9};求出所有元素的最大值,最小值,和值,平均值,并输出出来。
 */
public class ArrayTest2 {
    public static void main(String[] args) {
        //定义数组
        int[] arr = {1,3,11,5,7,9};
        //假设0下标是最大值 0下标是最小值
        int max = arr[0];
        int min = arr[0];
        int sum = 0;
        int avg = 0;
        //2.判断最大值和最小值
        for(int i=0;i<arr.length;i++) {
            if(max<arr[i]) {
                max = arr[i];
            }
            if(min>arr[i]) {
                min = arr[i];
            }
            sum+=arr[i];
        }
        avg = sum/arr.length;
        System.out.println("最大值"+max);
        System.out.println("最小值"+min);
        System.out.println("和是"+sum);
        System.out.println("平均值是"+avg);

    }
}

4.3 数组的复制

已知数组int[] arr1 = {1,3,5,7,9} , int[] arr2; 将数组arr1的内容复制到数组arr2中

参考答案:

/**
 * 已知数组int[] arr1 = {1,3,5,7,9} , int[] arr2; 将数组arr1的内容复制到数组arr2中
 */
public class ArrayTest3 {
    public static void main(String[] args) {
        //1.定义数组
        int[] arr1,arr2;
        //2.初始化
        arr1 = new int[]{1,3,5,7,9};
        //3.打印数组arr1
        for(int i=0;i<arr1.length;i++) {
            System.out.println(arr1[i]);
        }
        //4.数组复制操作
        arr2 = new int[arr1.length];
        for(int i=0;i<arr1.length;i++) {
            arr2[i] = arr1[i];
        }
    }
}

注意:切不可 arr2 = arr1 这不是复制数组内容,这是复制数组内存地址;arr2和arr1会指向同一块堆内存空间,改变arr2的同时也会改变arr1,改变arr1的同时也会改变arr2

4.4 数组的反转

已知一个数组如下String[] arr = new String[]{“AA”,“BB”,“CC”,“DD”,“EE”};,反转arr数组得到如下结果String[] arr = new String[]{“EE”,“DD”,“CC”,“BB”,“AA”};

参考答案:

/**
 * 已知一个数组如下String[] arr = new String[]{"AA","BB","CC","DD","EE"};,
 * 反转arr数组得到如下结果String[] arr = new String[]{"EE","DD","CC","BB","AA"};
 */
public class ArrayTest4 {
    public static void main(String[] args) {
        String[] arr = new String[]{"AA","BB","CC","DD","EE"};

        for(int i=0;i<arr.length/2;i++) {
            String str = arr[i];
            arr[i] = arr[arr.length-i-1];
            arr[arr.length-i-1] = str;

        }
        for(int i=0;i<arr.length;i++) {
            System.out.println(arr[i]);
        }
    }
}

五、二维数组的使用

如果说可以把一维数组当成几何中的线性图形, 那么二维数组就相当于是一个表格。就像下面图一样:

在这里插入图片描述

对于二维数组的理解,我们可以理解为一维数组的数组。既数组0下标是一个一维数组,1下标又是一个一维数组数组…。

5.1 二维数组的动态初始化

二维数组存在两种定义方式,第一种定义方式如下:

  • int[][]arr = new int[4][3]; 定义了名为arr的二维数组,二维数组中有4个一维数组 每一个一维数组中有3个元素
  • 一维数组分别为arr[0], arr[1], arr[2] ,arr[3]
  • 给第一个一维数组0脚标位赋值为1写法是:arr[0][0] = 1;
  • arr 数组的长度 arr.length;
  • arr[0].length 代表arr数组的0下标一维数组的长度。

示例:

/**
 * 二维数组动态初始化1
 */
public class ArrayDemo7 {
    public static void main(String[] args) {
        //1.动态定义二维数组方式1
        /*两种理解方式										        y  x
         * 	方式1 图形化理解  4 行 3 列 二维数组  int[][] arr = new int[4][3];
         *  方式2 有 4 个 一维数组  每个一维数组可以存放3个数
         */
        int[][] arr = new int[4][3];
        //2.获得 4 个一维数组 arr[0] arr[1] arr[2] arr[3]
        //打印 第0个数组
        System.out.print(arr[0][0]);
        System.out.print(arr[0][1]);
        System.out.println(arr[0][2]);
        //打印 第1个数组
        System.out.print(arr[1][0]);
        System.out.print(arr[1][1]);
        System.out.println(arr[1][2]);
        //打印 第2个数组
        System.out.print(arr[2][0]);
        System.out.print(arr[2][1]);
        System.out.println(arr[2][2]);
        //打印 第3个数组
        System.out.print(arr[3][0]);
        System.out.print(arr[3][1]);
        System.out.println(arr[3][2]);
        //3.查看二维数组长度
        System.out.println(arr.length);
        //4. 查看二维数组0下标长度
        System.out.println(arr[0].length);
        //5. 查看二维数组1标长度
        System.out.println(arr[1].length);
        //6. 查看二维数组2下标长度
        System.out.println(arr[2].length);
        //6. 查看二维数组3下标长度
        System.out.println(arr[3].length);
    }
}

第二种定义方式如下:

  • int[][] arr = new int[3][]; 二维数组中有3个一维数组。 每个一维数组都是默认初始化值null (注意:区别于格式1)
  • 可以对这个三个一维数组分别进行初始化 arr[0] = new int[3]; arr[1] = new int[2]; arr[2] = new int[1];

注: int[][]arr = new int[][3]; 这种写法是错误的

示例:

public class ArrayDemo8 {
	public static void main(String[] args) {
		//1.动态初始化2   
		/**
		 *   图形化理解  定义 4行 图形 几列待定
		 *  定义 4 个 一维数组  一维数组内容 没有初始化 
		 */
		int[][] arr = new int[4][];
		//2.定义arr[0] 一维数
		arr[0] = new int[1];
		//3.定义arr[1] 一维数
		arr[1] = new int[2];
		//4.定义arr[2] 一维数
		arr[2] = new int[3];
		//5.定义arr[3] 一维数
		arr[3] = new int[4];
		//6.查看 数组长度
		System.out.println(arr.length);
		//7.查看0下标数组长度
		System.out.println(arr[0].length);
		//8.查看1下标数组长度
		System.out.println(arr[1].length);
		//9.查看2下标数组长度
		System.out.println(arr[2].length);
		//10.查看3下标数组长度
		System.out.println(arr[3].length);
	}
}

5.2 二维数组的静态初始化

int[][] arr = new int[][]{{1},{1,2},{1,2,3}}; 定义一个名称为arr的二维数组,二维数组中有三个一维数组

每一个一维数组中具体元素也都已初始化 第一个一维数组 arr[0] = {1}; 第二个一维数组 arr[1] = {1,2}; 第三个一维数组 arr[2] = {1,2,3};

以上代码也可以简写为:int[][] arr = {{1},{1,2},{1,2,3}};

示例:

public class ArrayDemo9 {
    public static void main(String[] args) {
        //1.二维数组静态初始化
        int[][] arr = new int[][] {
                {1,1,1},
                {2,2,2},
                {3,3,3}
        };
        //2.简化
        int[][] arr2 = {
                {1},
                {2,2},
                {3,3,3}
        };
    }
}

5.3 二维数组的遍历

二维数组循环赋值与遍历过程如下

public class ArrayDemo10 {
    public static void main(String[] args) {
        //1.矩形
        int[][] arr1 = new int[4][3];
        //2.循环赋值
        for(int y=0;y<arr1.length;y++) {
            for(int x=0;x<arr1[y].length;x++) {
                arr1[y][x] = 1;
            }
        }
        //3.循环遍历
        for(int y=0;y<arr1.length;y++) {
            for(int x=0;x<arr1[y].length;x++) {
                System.out.print(arr1[y][x]+"\t");
            }
            System.out.println();
        }
        //2.直角三角形练习
        String[][] arr2 = new String[4][];
        //3.循环赋值
        for(int y=0;y<arr2.length;y++) {
            //4.定义一维数组
            arr2[y] = new String[y+1];
            for(int x=0;x<arr2[y].length;x++) {
                arr2[y][x] = "*";
            }
        }
        //4.打印二维数组
        for(int y=0;y<arr2.length;y++) {
            for(int x=0;x<arr2[y].length;x++) {
                System.out.print(arr2[y][x]);
            }
            System.out.println();
        }
    }
}

5.4 小结

  1. 二维数组的动态初始化

  2. 二维数组的静态初始化

  3. 二维数组的遍历

六、二维数组练习题

6.1 杨辉三角

使用二维数组打印一个10行的杨辉三角

在这里插入图片描述

参考答案:

public class ArrayDemo11 {
    public static void main(String[] args) {
        //1.定义杨辉三角二维数组
        int[][] arr = new int[10][];
        //2.循环初始化 二维数组
        for(int y=0;y<arr.length;y++) {
            arr[y] = new int[y+1];
            //3.给每一行的第一个值和最后一个值赋值为 1
            arr[y][0] = arr[y][y] = 1;
            //4.给其他位置赋值
            //if(y>1) {
            for(int x=1;x<arr[y].length-1;x++) {
                arr[y][x] = arr[y-1][x-1]+arr[y-1][x];
            }
            //}

        }
        //3.遍历
        for(int y=0;y<arr.length;y++) {
            for(int x=0;x<arr[y].length;x++) {
                System.out.print(arr[y][x]+"\t");
            }
            System.out.println();
        }
    }
}

七、数组中常见算法

7.1 二分查找算法

已知数组int[] arr = {1,3,5,7,9,11,13};通过二分查找法查找数组中是否包含元素3,如果包含,元素3的下标是多少?注意(只有排好序的数组才能使用二分查找法)

分析过程如下:

在这里插入图片描述

另一种情况,当查找元素大于中间元素middle过程如下,这里以查找13为例

在这里插入图片描述

参考代码:

/**
 * 数组元素二分查找法,前提:已排序的数组
 */
public class BinarySearchArray {
    public static void main(String[] args) {
        //定义数组
        int[] arr = {1,3,5,7,9,11,13};
        // 定义查找目标数
        int target = 3;
        //开始下标
        int head = 0;
        //结束下标
        int end = arr.length-1;
        //标记是否找到目标元素
        boolean tag = true;
        //二分查找
        while(head<=end){
            int middle = (head+end)/2;
            if(arr[middle]==target){
                System.out.println("查找到元素:"+target+",下标:"+middle);
                tag = false;
                break;
            }else if(arr[middle]>target){
                end=middle-1;
            } else {
                head=middle+1;
            }
        }
        if(tag){
            System.out.println("没有找到目标元素"+target);
        }
    }
}

7.2 数组的排序介绍(其余排序,由于算法过于复杂,后期统一讲)

排序:是计算机程序设计中的一项重要操作,是指对数组或集合中的元素进行按照大小或字母排序。

排序的算法有很多很多种,这里以冒泡排序、选择排序、插入排序为例进行讲解。

7.3 冒泡排序

冒泡排序的设计思想:从0下标开始比较相邻元素,通过交换下标元素位置,把大的元素放后面,小的元素放前面, 比较完一轮完成最后一个元素是最大的,以此类推,经过n轮比较完成排序的过程。

在这里插入图片描述

代码实现分析

  1. 一共比较几轮?
  2. 每轮比较几次?

参考答案

/**
 * 冒泡排序
 */
public class SortDemo1 {
    public static void main(String[] args) {
        //定义数组
        int[] arr = {1,11,9,3,7,5};
        //排序
        for(int i=0;i<arr.length-1;i++){ //如果有6个数,比较5轮就可以了,剩下一个一定是最小的
            // 因为是j和j+1比较所以j<arr.length-1,又因为每比较一次,就少比较一个数,
            // 所以j<arr.length-1-i;
            for(int j=0;j<arr.length-1-i;j++){
                // 比较相邻元素,交换相邻下标位置
                if(arr[j]>arr[j+1]){
                    int t = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = t;
                }
            }
        }
        //打印数组
        for(int i=0;i<arr.length;i++){
            System.out.println(arr[i]);
        }
    }
}

7.4 选择排序

选择排序的思路是:

  1. 将0下标和后面所有元素比,如果0下标不是最小元素,就交换位置,比较完一轮0下标就是最小的元素
  2. 以此类推将1下标元素和后面所有元素比较,如果1下标不是最小元素,就交换位置,比较完一轮1下标就第二小的元素
  3. 依此类推,完成整个数组的排序

在这里插入图片描述

代码实现分析

  1. 一共比较几轮?
  2. 每轮比较几次?

参考答案:


/**
 * 选择排序
 */
public class SortDemo2 {
    public static void main(String[] args) {
        //定义数组
        int[] arr = {1,11,9,3,7,5};
        //选择排序
        for(int i=0;i<arr.length-1;i++){ //如果6个数,比较5轮即可,剩下最后一个一定是最大的
            //让0下标i和后面所有下标比较;所以开始是i+1 结束到最大下标
            for(int j=i+1;j<arr.length;j++){
                if(arr[i]>arr[j]){
                    int t = arr[i];
                    arr[i] = arr[j];
                    arr[j] = t;
                }
            }
        }
        //打印数组
        for(int i=0;i<arr.length;i++){
            System.out.println(arr[i]);
        }
    }
}

7.5 插入排序

插入排序的设计思路是:

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤2~5

在这里插入图片描述

参考答案:

/**
 * 插入排序
 */
public class SortDemo3 {
    public static void main(String[] args) {
        //定义数组
        int[] arr = {1,11,9,3,7,5};
        //插入排序
        for(int index = 1;index<arr.length;index++){
            int t = arr[index];
            int leftIndex = index-1;
            while(leftIndex>=0 && arr[leftIndex]>t){
                arr[leftIndex+1] = arr[leftIndex];
                leftIndex--;
            }
            arr[leftIndex+1] = t;
        }
        //打印数组
        for(int i=0;i<arr.length;i++){
            System.out.println(arr[i]);
        }
    }
}

7.6 小结

  1. 二分查找

  2. 冒泡排序

  3. 选择排序

  4. 插入排序

八、数组中常见的异常

数组中的常见异常:

  • 数组角标越界的异常:ArrayIndexOutOfBoundsExcetion
  • 空指针异常:NullPointerException

九、总结

  1. 一维数组的使用

  2. 二维数组的使用

  3. 一维数组的常见算法:查找和排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值