04-java数组

目录

第4章 数组

4.1 数组的概念

4.1.1 容器概述

4.1.2 数组的概念

4.1.3 数组的分类

4.2 一维数组的声明与使用

4.2.1 一维数组的声明

4.2.2 一维数组的静态初始化

4.2.3 一维数组的使用

4.2.4 数组下标越界异常

4.2.4 一维数组的遍历

4.2.5 一维数组动态初始化

4.2.6 数组元素的默认值

4.3 一维数组内存分析

4.3.1 内存概述

4.3.2 Java虚拟机的内存划分

4.4.3 一维数组在内存中的存储

1、一个一维数组内存图

2、数组下标为什么是0开始

3、两个一维数组内存图

4、两个变量指向一个一维数组

4.4 一维数组的常见算法

4.4.1 数组统计:求总和、均值、统计偶数个数等

4.4.2 数组找最值

1、找最大值/最小值

2、找最值及其第一次出现的下标

4.4.3 数组的元素查找

1、顺序查找

2、二分查找

4.4.4 数组元素排序

1、排序算法概述

2、直接选择排序

3、冒泡排序

4、冒泡排序优化

4.5 二维数组

4.5.1 二维数组的静态初始化

4.5.2 获取二维数组长度

4.5.3获取二维数组中的元素

4.5.4二维数组的动态初始化


第4章 数组

4.1 数组的概念

4.1.1 容器概述

  • 生活中的容器:衣柜(装衣服等物品),教室(装学生等人员)。

  • 程序中的容器:是将多个数据存储到一起,每个数据称为该容器的元素。

4.1.2 数组的概念

  • 数组概念: 数组就是用于存储数据的长度固定的容器,保证多个数据的数据类型要一致。

数组的定义:

所谓数组(array),就是相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,以便统一管理他们,然后用编号区分他们,这个名字称为数组名,编号称为下标或索引(index)。组成数组的各个变量称为数组的元素(element)。数组中元素的个数称为数组的长度(length)。

4.1.3 数组的分类

1、按照维度分:

  • 一维数组:存储一组数据。

  • 二维数组:存储多组数据,相当于二维表,一行代表一组数据,这是这里的二维表每一行长度不要求一样。

2、按照元素类型分:

  • 基本数据类型的元素:存储数据值

  • 引用数据类型的元素:存储对象(本质上存储对象的首地址)(这个在面向对象部分讲解)

注:无论数组的元素是基本数据类型还是引用数据类型,数组本身都是引用数据类型。

4.2 一维数组的声明与使用

4.2.1 一维数组的声明

  • 一维数组的声明/定义格式

//推荐
元素的数据类型[] 数组名;
​
//不推荐
元素的数据类型  数组名[];
  • 数组的声明,就是要确定:

(1)数组的维度:在Java中数组的标点符号是[],[]表示一维,[][]表示二维

(2)数组的元素类型:即创建的数组容器可以存储什么数据类型的数据。元素的类型可以是任意的Java的数据类型。例如:int, String等

(3)数组名:就是代表某个数组的标识符,数组名其实也是变量名,按照变量的命名规范来命名。数组名是个引用数据类型的变量,因为它代表一组数据。

4.2.2 一维数组的静态初始化

  • 什么是初始化?

    • 初始化就是确定数组元素的总个数(即数组的长度)和元素的值

  • 什么是静态初始化?

    • 静态初始化就是用静态数据(编译时已知)为数组初始化。此时数组的长度由静态数据的个数决定。

  • 一维数组静态初始化格式1:

数据类型[] 数组名 = {元素1,元素2,元素3...};//必须在一个语句中完成,不能分开两个语句写
例如,定义存储1,2,3,4,5整数的数组容器

int[] arr = {1,2,3,4,5};//正确
​
int[] arr;
arr = {1,2,3,4,5};//错误
  • 一维数组静态初始化格式2:

数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
或
数据类型[] 数组名;
数组名 = new 数据类型[]{元素1,元素2,元素3...};
例如,定义存储1,2,3,4,5整数的数组容器。

int[] arr = new int[]{1,2,3,4,5};//正确
​
int[] arr;
arr = new int[]{1,2,3,4,5};//正确

4.2.3 一维数组的使用

  • 如何获取数组的元素总个数,即数组的长度

数组的长度属性: 每个数组都具有长度,而且是固定的,Java中赋予了数组的一个属性,可以获取到数组的长度,语句为:数组名.length ,属性length的执行结果是数组的长度,int类型结果。

数组名.length
  • 如何表示数组中的一个元素?

每一个存储到数组的元素,都会自动的拥有一个编号,从0开始,这个自动编号称为数组索引(index)或下标,可以通过数组的索引/下标访问到数组中的元素。

数组名[索引/下标]

  • 数组的下标范围?

Java中数组的下标从[0]开始,下标范围是[0, 数组的长度-1],即[0, 数组名.length-1]

4.2.4 数组下标越界异常

当访问数组元素时,下标指定超出[0, 数组名.length-1]的范围时,就会报数组下标越界异常:ArrayIndexOutOfBoundsException。

public class Test04ArrayIndexOutOfBoundsException {
    public static void main(String[] args) {
        int[] arr = {1,2,3};
       // System.out.println("最后一个元素:" + arr[3]);//错误,下标越界ArrayIndexOutOfBoundsException
      //  System.out.println("最后一个元素:" + arr[arr.length]);//错误,下标越界ArrayIndexOutOfBoundsException
        System.out.println("最后一个元素:" + arr[arr.length-1]);//对
    }
}

创建数组,赋值3个元素,数组的索引就是0,1,2,没有3索引,因此我们不能访问数组中不存在的索引,程序运行后,将会抛出 ArrayIndexOutOfBoundsException 数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。

4.2.4 一维数组的遍历

数组遍历: 就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石。for循环与数组的遍历是绝配。

public class Test05ArrayIterate {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};
        //打印数组的属性,输出结果是5
        System.out.println("数组的长度:" + arr.length);

        //遍历输出数组中的元素
        System.out.println("数组的元素有:");
        for(int i=0; i<arr.length; i++){
            System.out.println(arr[i]);
        }
    }
}

4.2.5 一维数组动态初始化

  • 什么是动态初始化?

动态初始化就是先确定元素的个数(即数组的长度),而元素此时只是默认值,并不是真正的数据。元素真正的数据需要后续单独一个一个赋值。

  • 格式:

 数组存储的元素的数据类型[] 数组名 = new 数组存储的元素的数据类型[长度];
数组存储的数据类型[] 数组名;
 数组名字 = new 数组存储的数据类型[长度];
  • new:关键字,创建数组使用的关键字。因为数组本身是引用数据类型,所以要用new创建数组对象。

  • [长度]:数组的长度,表示数组容器中可以存储多少个元素。

  • 注意:数组有定长特性,长度一旦指定,不可更改。和水杯道理相同,买了一个2升的水杯,总容量就是2升是固定的。

4.2.6 数组元素的默认值

当我们使用动态初始化方式创建数组时,元素只是默认值。

4.3 一维数组内存分析

4.3.1 内存概述

内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。

Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。

4.3.2 Java虚拟机的内存划分

为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

区域名称作用
程序计数器程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址
本地方法栈当程序中调用了native的本地方法时,本地方法执行期间的内存区域
方法区存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
堆内存存储对象(包括数组对象),new来创建的,都存储在堆内存。
虚拟机栈用于存储正在执行的每个Java方法的局部变量表等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完,自动释放。

4.4.3 一维数组在内存中的存储

1、一个一维数组内存图
public static void main(String[] args) {
  	int[] arr = new int[3];
  	System.out.println(arr);//[I@5f150435
}

思考:打印arr为什么是[I@5f150435,它是数组的地址吗?

答:它不是数组的地址。

问?不是说arr中存储的是数组对象的首地址吗?

答:arr中存储的是数组的首地址,但是因为数组是引用数据类型,打印arr时,会自动调用arr数组对象的toString()方法,该方法默认实现的是对象类型名@该对象的hashCode()值的十六进制值。

问?对象的hashCode值是否就是对象内存地址?

答:不一定,因为这个和不同品牌的JVM产品的具体实现有关。例如:Oracle的OpenJDK中给出了5种实现,其中有一种是直接返回对象的内存地址,但是OpenJDK默认没有选择这种方式。

2、数组下标为什么是0开始

因为第一个元素距离数组首地址间隔0个单元格。

3、两个一维数组内存图

两个数组独立

public static void main(String[] args) {
    int[] arr = new int[3];
    int[] arr2 = new int[2];
    System.out.println(arr);
    System.out.println(arr2);
}

4、两个变量指向一个一维数组

两个数组变量本质上代表同一个数组。

public static void main(String[] args) {
    // 定义数组,存储3个元素
    int[] arr = new int[3];
    //数组索引进行赋值
    arr[0] = 5;
    arr[1] = 6;
    arr[2] = 7;
    //输出3个索引上的元素值
    System.out.println(arr[0]);
    System.out.println(arr[1]);
    System.out.println(arr[2]);
    //定义数组变量arr2,将arr的地址赋值给arr2
    int[] arr2 = arr;
    arr2[1] = 9;
    System.out.println(arr[1]);
}

4.4 一维数组的常见算法

4.4.1 数组统计:求总和、均值、统计偶数个数等

示例代码1:

        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        double avg = (double) sum / arr.length;
        System.out.println("总和是:" + sum);
        System.out.println("平均值是:" + avg);

示例代码2:

        int product = 1;
        for (int i = 0; i < arr.length; i++) {
            product *= arr[i];
        }
        System.out.println("总乘积是:" + product);

示例代码3:

public class Test10ArrayElementEvenCount {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};
        //统计偶数个数
        int evenCount = 0;
        for(int i=0; i<arr.length; i++){
            if(arr[i]%2==0){
                evenCount++;
            }
        }

        System.out.println("evenCount = " + evenCount);
    }
}

4.4.2 数组找最值

1、找最大值/最小值

思路:

(1)先假设第一个元素最大/最小

(2)然后用max/min与后面的元素一一比较

示例代码:

public class Test11ArrayMax {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};
        //找最大值
        int max = arr[0];
        for(int i=1; i<arr.length; i++){//此处i从1开始,是max不需要与arr[0]再比较一次了
            if(arr[i] > max){
                max = arr[i];
            }
        }
        System.out.println("max = " + max);
    }
}
2、找最值及其第一次出现的下标

思路:

(1)先假设第一个元素最大/最小

(2)用max/min变量表示最大/小值,用max/min与后面的元素一一比较

(3)用index时刻记录目前比对的最大/小的下标

示例代码:

public class Test12MaxIndex {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};
        //找最大值以及第一个最大值下标
        int max = arr[0];
        int index = 0;
        for(int i=1; i<arr.length; i++){
            if(arr[i] > max){
                max = arr[i];
                index = i;
            }
        }
        System.out.println("max = " + max);
        System.out.println("index = " + index);
    }
}

或思路:

(1)先假设第一个元素最大/最小

(2)用maxIndex时刻记录目前比对的最大/小的下标,那么arr[maxIndex]就是目前的最大值

public class Test12MaxIndex2 {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};
        //找最大值
        int maxIndex = 0;
        for(int i=1; i<arr.length; i++){
            if(arr[i] > arr[maxIndex]){
                maxIndex = i;
            }
        }
        System.out.println("最大值:" + arr[maxIndex]);
    }
}

4.4.3 数组的元素查找

1、顺序查找

顺序查找:挨个查看

要求:对数组元素的顺序没要求

顺序查找示例代码:

public class ArrayCaseOrderSearch15 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int[] arr = {2, 11, 55, 2, 3, 4};
        System.out.print("请输入您要查找的值:");
        int num = scan.nextInt();
        int index = -1;
 
        for (int i = 0; i < arr.length; i++) {
            if (num == arr[i]) {
                index = i;
                break;
            }
        }
        if (index != -1) {
            System.out.println(num + "的数组下标是:" + index);
        } else {
            System.out.println("在此数组中查找不到" + num + "!");
        }
    }
}
2、二分查找
import java.util.Scanner;

public class Test15ArrayBinarySearch {
    public static void main(String[] args){
        //数组一定是有序的
        int[] arr = {8,15,23,35,45,56,75,85};

        Scanner input = new Scanner(System.in);
        System.out.print("请输入你要查找的值:");
        int target = input.nextInt();

        int index = -1;
        for(int left = 0,right = arr.length-1; left<=right; ){
            //int mid = (left+right)/2;
            int mid = left + (right-left)/2;

            if(arr[mid] == target){
                index = mid;
                break;
            }else if(target > arr[mid]){
                //说明target在[mid]右边
                left = mid+1;
            }else{
                //说明target<arr[mid],target在[mid]左边
                right= mid-1;
            }
        }
        if(index!=-1){
            System.out.println("找到了,下标是"+index);
        }else{
            System.out.println("不存在");
        }

    }
}

4.4.4 数组元素排序

1、排序算法概述

数组的排序算法很多,实现方式各不相同,时间复杂度、空间复杂度、稳定性也各不相同:

  • 时间复杂度:

常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)

一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
  • 空间复杂度:

类似于时间复杂度的讨论,一个算法的空间复杂度(Space Complexity)S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。
  • 稳定性:

排序一定会设计到数组元素位置的交换。如果两个元素相等,无论它们原来是否相邻,在排序过程中,最后它们变的相邻,但是它们前后顺序并没有改变,就称为稳定的,否则就是不稳定的。

2、直接选择排序
public class SelectOrder17 {
    public static void main(String[] args) {
        int[] arr = {2, 11, 55, 2, 3, 4};
 
        //按照循环设定目标位置
        //轮数 = 数组的元素总个数-1
        for (int i = 0; i < arr.length-1; i++) {
            //目标后面的元素进行一一比较
            int min = arr[i];
            int index = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < min) {
                    min = arr[j];
                    index = j;
                }
            }
            //交换数值
            if (index != i) {
                int temp = arr[i];
                arr[i] = arr[index];
                arr[index] = temp; 
            }
        }
        //完成排序,遍历结果
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "  ");
        }
    }
}
3、冒泡排序
public class BubbleOrder18 {
    public static void main(String[] args) {
        int[] arr = {2, 11, 55, 2, 3, 4};
 
        //冒泡排序
        //趟数,每趟产生一个最值放在最右端
        for (int i = 0; i < arr.length - 1; i++) {
            //比较次数,由于每次减少一个比较数,所以减去1
            for (int j = 0; j < arr.length - i - 1; j++) {
                //交换
                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));
    }
}
4、冒泡排序优化
public class BubbleOrder19 {
    public static void main(String[] args) {
        int[] arr = {2, 2, 3, 4, 11, 55};
 
        int tang = 0;
        int count = 0;
        //冒泡排序
        //趟数,每趟产生一个最值放在最右端
        for (int i = 0; i < arr.length - 1; i++) {
 
            Boolean flag = true;
            //比较次数,由于每次减少一个比较数,所以减去1
            for (int j = 0; j < arr.length - i - 1; j++) {
                //交换
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = false;
                }
                count++;
            }
            if (flag) {
                break;
            }
            tang++;
        }
        System.out.println("次数" + count);
        System.out.println("趟数" + tang);
        System.out.println(Arrays.toString(arr));
    }
}

4.5 二维数组

概述:数组中的套多个数组

4.5.1 二维数组的静态初始化

        //二维数组初始化
        //静态初始化
        int[][] secArr1 = {{1, 2}, {3, 4}};
        int[][] secArr2 = {
                {1, 2},
                {3, 4, 5, 6},
                {1, 2}
        };

4.5.2 获取二维数组长度

格式:数组名.length

        //获取二维数组的长度
        System.out.println(secArr2.length);

4.5.3获取二维数组中的元素

        //获取二维数组中的数据
        for (int i = 0; i < secArr2.length; i++) {
            for (int j = 0; j < secArr2[i].length; j++) {
                System.out.print(secArr2[i][j]+" ");
            }
            System.out.println();
        }

4.5.4二维数组的动态初始化

        //动态初始化
        int[][] arr1 = new int[5][3];
        //循环给值
        for (int i = 0; i < arr1.length; i++) {
            for (int j = 0; j < arr1[i].length; j++) {
                arr1[i][j] = i * 2;
            }
        }
        //循环输出
        for (int i = 00; i < arr1.length; i++) {
            for (int j = 0; j < arr1[i].length; j++) {
                System.out.print(arr1[i][j] + " ");
            }
            System.out.println();
        }

  • 25
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 动态数组是一种可以根据需要动态增加或减少大小的数组。在Java中,动态数组可以使用ArrayList类来实现。ArrayList类提供了一些方法来添加、删除、获取和修改元素。与普通数组不同的是,ArrayList可以自动调整大小,因此不需要手动管理数组大小。 ### 回答2: 在Java中,数组是存储一组同类型元素的有效数据结构。通常,当我们需要定义数组但无法确定其长度时,可以使用动态数组。与静态数组相比,动态数组可以在程序运行时动态地改变其大小。它不需要分配整个内存块,而是可以按需增加或减少其大小。Java通过ArrayList类来实现动态数组。 要使用ArrayList类,需要导入Java.util包,然后定义一个ArrayList变量。与静态数组不同,对动态数组进行元素的添加或删除不需要重新定义整个数组。因此,对于频繁变化的数据结构,动态数组是一种更为灵活和高效率的选项。 ArrayList类有许多有用的方法,例如add(),remove(),size(),get()等。使用add()方法可以将一个元素添加到动态数组的末尾。如果需要在指定位置添加元素,则可以使用add(int index, Object element)方法。remove()方法可以从数组中删除一个元素。size()方法可以返回动态数组目前的大小,而get()方法可以按照索引值返回数组中的元素。 虽然动态数组的使用便捷和高效,在使用时需要注意一些细节问题。因为动态数组内部使用了一个数组,所以频繁地添加和删除元素会导致内部数组的扩充和缩小,从而降低性能。在处理大量数据时,我们应该考虑使用其他数据结构,例如链表。 总之,动态数组Java编程中非常常用,特别是在需要不确定数组长度的情况下。熟练掌握动态数组的使用方法,可以提高代码的效率和可读性,同时也丰富了Java的数据结构知识。 ### 回答3: 动态数组,也称为可调整数组,是一种支持动态内存分配的数组类型。与静态数组不同,动态数组的大小在程序运行时可以动态调整。在Java中,动态数组可以使用数组列表(ArrayList)或Vector来实现。 ArrayList是Java中常用的动态数组类。声明和初始化一个ArrayList的方法如下: ```java ArrayList<String> list = new ArrayList<String>(); ``` 在这个示例中,ArrayList中存储的是字符串类型的元素。如果要存储其他类型的元素,只需相应地将“String”替换为相应的类型即可。 向ArrayList中添加元素的方法是“add”方法。例如,在上面的示例中,我们可以使用以下代码向ArrayList中添加元素: ```java list.add("apple"); // 添加元素"apple"到列表中 ``` 获取ArrayList中元素的方法是“get”方法。例如: ```java String element = list.get(0); // 获取列表中索引为0的元素 ``` 需要注意的是,ArrayList和Vector都是动态数组类型,它们的区别在于线程同步。Vector是线程安全的,而ArrayList非线程安全。因此,在多线程环境下使用动态数组时,建议使用Vector。 除了ArrayList和Vector之外,还有其他的动态数组实现方式,比如LinkedList、CopyOnWriteArrayList等。 总的来说,动态数组是一种非常常用的数据结构类型,它具有动态调整大小的优势,适用于需要频繁插入和删除元素的情况。在Java中,我们可以使用ArrayList或Vector来实现动态数组,并根据需要选择合适的实现方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值