数组

mac2026-04-21  8

一、概述

       数组:就是用于存储【相同数据类型】的数据的【容器】。

       为什么要使用数组:没有数组,存在多个变量,需要声明多个变量的名称,这些名称之间没有什么关联,想访问所有的变量,比较困难。有了数组,只需要有一个数组容器的名称,容器里面有通过数字表示位置。同时这些数字位置有规律,结合数组名称非常容易的去访问所有的变量。数字位置可以称为索引,数组在内存中开辟了一块连续的内存空间。

二、定义和初始化

1.数组的定义格式

       格式1:数据类型[] 数组名;(推荐使用)  如: int[] nums ;

       格式2:数据类型 数组名[]; (兼容c语言的格式) 如 int nums[]

2.数组初始化

       所谓初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。

       注意:Java中的数组必须先初始化,然后才能使用。

     (1)动态初始化

     格式:数据类型[] 数组名 = new 数据类型[数组长度];  

     举例:int[] arr = new int[3]; //解释:定义了一个int类型的数组,这个数组中可以存放3个int类型的值。

     详细解释

public static void main(String[] args) { int[] arr = new int[3]; System.out.println(arr);//[I@5f150435 }

     以上方法执行,输出的结果是[I@5f150435,这个是什么呢?是数组在堆内存中的地址。

     [:表示一个一维数组。(如果是[[,表示二维数组)

     I:表示数组中存放的是int类型的数组

     @:连接符,没有实际意义

     5f150435:表示数组中的起始的内存地址值。数组名称 arr  可以存数组的地址。

     注意:new出来的内容,都是在堆内存中存储的,而方法中的变量arr保存的是数组的地址。

     (2)静态初始化

     格式:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…}; 

     举例:int[] arr = new int[]{1,2,3}; //解释:定义了一个int类型的数组,这个数组中可以存放3个int类型的值,并且值分别是1,2,3。

     简化格式:数据类型[] 数组名 = {元素1,元素2,...};

     举例:int[] arr = {1,2,3};

3.访问数组元素

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

     格式:数组名[索引]

     数组的长度属性

     每个数组都具有长度,而且是固定的,Java中赋予了数组的一个属性,可以获取到数组的长度。

     语句为: 数组名.length ,属性length的执行结果是数组的长度,int类型结果。

     由此可以推断出,数组的最大索引值为数组名.length-1 。

class Test { public static void main(String[] args){ int[] arr = {1,2,3,4,5}; System.out.println(arr.length);//5 }

     索引访问数组中的元素

     数组名[索引]=数值,为数组中的元素赋值。

     变量=数组名[索引],获取出数组中的元素。

     

三、数组内存图

1.概念

     内存是计算机中的重要元件,可以用来给程序临时存储数据。我们编写的程序,必须放进内存中才能运行,运行完毕后会清空内存。Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。

2.JVM内存划分

     JVM是执行java程序的容器,空间很大,需要划分不同的空间,不同的功能,需要使用不同的取余来指定完成。分为:[栈内存,方法区,堆内存,本地方法区,程序计数器]

     桟内存:用于执行方法,每个方法单独分配一段空间,称为栈帧,把给方法分配内存空间,形象的称为“进栈”。特点:先进后出。

     堆内存:用于存储数组,对象等数据量较大的数据,一般都是引用数据类型。

     方法区:用于存储类的字节码对象,存储常量,存储静态变量

     本地方法区:用于执行本地方法。C语言,C++语言方法就是本地方法

     程序计数器:用于控制程序的执行、控制程序执行到哪行代码

3.数组在内存中的存储

     (1)一个数组的内存图

     

     (2)两个数组的内存图

     

     (3)两个变量指向一个数组

     

     (4)程序的执行流程

     

四、数组常见错误

1.数组索引越界异常

     每个数组的索引都有一个范围,即0~length-1。在访问数组的元素时,索引不能超出这个范围,否则程序会报错,如下所示:

class Test { public static void main(String[] args){ int[] arr = new int[4]; // 定义一个长度为4的数组 System.out.println("arr[4]=" + arr[4]); // 通过角标4访问数组元素 } }

     上面运行结果中所提示的错误信息是数组越界异常ArrayIndexOutOfBoundsException,出现这个异常的原因是数组的长度为4,其索引范围为0~3,而上述代码中的第4行代码使用索引4来访问元素时超出了数组的索引范围。

2.空指针异常

     数组未经过初始化,直接调用为null,程序会报错。(java.lang.NullPointerException)如下所示:       

class Test { public static void main(String[] args){ int[] arr = new int[2]; arr=null; System.out.println(arr[0]);//访问空的报错 } }

五、数组操作

1.数组的遍历

     方法1

class Test { public static void main(String[] args){ int[] arr = {1,2,3,4,5}; for(int i=0;i<arr.length;i++){ System.out.println(arr[i]); } } }

     方法2

import java.util.Arrays; class Test { public static void main(String[] args){ int[] arr = {1,2,3,4,5}; System.out.println(Arrays.toString(arr)); } }

2.数组的最值

//分别定义方法,求一个整数数组的最大值、最小值、平均值和所有数组元素的和(4个方法) class Test { public static void main(String[] args) { int[] arr = {2,4,6,1,9,7,8,5,3,0}; System.out.println("数组的最大值为:"+getMax(arr)); System.out.println("数组的最小值为:"+getMin(arr)); System.out.println("数组的平均值为:"+aveArr(arr)); System.out.println("数组元素的和为:"+sumArr(arr)); } //求数组的最大值 public static int getMax(int[] arr){ int max = arr[0]; for(int i=1;i<arr.length;i++){ if(max<arr[i]){ max = arr[i]; } } return max; } //求数组的最小值 public static int getMin(int[] arr){ int min = arr[0]; for(int i=1;i<arr.length;i++){ if(min>arr[i]){ min = arr[i]; } } return min; } //求数组的平均值 public static double aveArr(int[] arr){ double ave = 0; double sum = 0; for(int i=0;i<arr.length;i++){ sum+=arr[i]; } ave = sum/arr.length; return ave; } //求数组元素的和 public static int sumArr(int[] arr){ int sum = 0; for(int i=0;i<arr.length;i++){ sum += arr[i]; } return sum; } }

3.数组的反转

     方法1

//数组反转 int[] a = {1,2,3,4,5}; class Test { public static void main(String[] args) { int[] a = {1,2,3,4,5}; int[] b = new int[5]; for(int i=0;i<5;i++){ b[4-i] = a[i]; } for(int i=0;i<b.length;i++){ System.out.print(b[i]+" "); } System.out.println(); } }

     方法2

//数组反转 int[] a = {1,2,3,4,5};不能新开数组(不能重新定义另外的数组) class Test { public static void main(String[] args) { int[] arr = {1,2,3,4,5}; revArr(arr); for(int i=0;i<arr.length;i++){ System.out.print(arr[i]+" "); } System.out.println(); } public static void revArr(int[] arr){ int temp; for(int i=0;i<arr.length/2;i++){ temp = arr[i]; arr[i] = arr[arr.length-1-i]; arr[arr.length-1-i] = temp; } } }

4.排序算法复杂度

5.冒泡排序

     基本思想:比较相邻的元素,如果第一个比第二个大,就交换他们两个,对每一对相邻元素作同样的工作,从开始第一对到结尾最后一对。在这一点,最后的元素应该会是最大的数,针对所有的元素重复以上的步骤,除了最后一个,持续每次对越来越少的元素重复上面的步骤,知道没有任何一对数字需要比较。

     算法:

class Test { public static void main(String[] args){ int[] arr={9,4,8,3,5,2,7,6,1}; //遍历输出原数组 for(int n=0;n<arr.length;n++){ System.out.print(arr[n]+" "); } System.out.println("\n"+"-----------------"); //排序 for(int i=0;i<arr.length-1;i++){ for(int j=0;j<arr.length-1-i;j++){ if(arr[j]>arr[j+1]){ //交换两个数的值(该方法可参考 ##java基本语法 -> 10 -> 方法二.交换两个数的值## ) arr[j] = arr[j] + arr[j+1]; arr[j+1] = arr[j] - arr[j+1]; arr[j] = arr[j] - arr[j+1]; } } //遍历一次,输出一次结果 for(int k=0;k<arr.length;k++){ System.out.print(arr[k]+" "); } System.out.println(); } } }

6.选择排序

     基本思想:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序列的数列的最后,知道全部待排序的数据元素排完

     算法:

class Test { public static void main(String[] args){ int[] arr={9,4,8,3,5,2,7,6,1}; //遍历输出原数组 for(int n=0;n<arr.length;n++){ System.out.print(arr[n]+" "); } System.out.println("\n"+"-----------------"); //排序 for(int i=0;i<arr.length-1;i++){ int min=i;//定义一个最小值,用来获取每次排序后最小值的索引 for(int j=i+1;j<arr.length;j++){ if(arr[min]>arr[j]) min = j; } if(min != i){ //如果每次对比完最小值下标不是开始的i,则将最小值下标代表的数和索引i表示的数进行交换,(即每次排序完将最小值放在排序的数的最前面) int temp = arr[min]; arr[min] = arr[i]; arr[i] = temp; } //每趟排序完输出 for(int k=0;k<arr.length;k++){ System.out.print(arr[k]+" "); } System.out.println(); } } }

7.插入排序

     基本思想:从后向前找到合适位置后插入,每步将一个待排序的记录,按其顺序吗大小插入到前面已经排序的子序列的合适位置(从后向前找到合适位置后),直到数据全部插入完为止

     算法:

class Test { public static void main(String[] args){ int[] arr={9,4,8,10,5,2,7,6,1}; //遍历原数组 for(int n:arr){ System.out.print(n+" "); } System.out.println("\n"+"---------------"); //从第二个数开始向前插入 for(int i=1;i<arr.length;i++){ int temp = arr[i];//记录操作数 int j=0; //排序 for(j=i-1;j>=0;j--){ if(arr[j]>temp){ arr[j+1] = arr[j]; //如果前面的数大于右边的数,将左边的数赋值给右边的数 }else{ break; } } if(arr[j+1]!=temp){ arr[j+1]=temp; } //遍历 for(int n:arr){ System.out.print(n+" "); } System.out.println(); } } } /* 9,4,8,10,5,2,7,6,1 i=1: temp=4 j=0 (a0=9 > temp=4) a1=9 9,9,8,10,5,2,7,6,1 j-1=-1(不满足循环条件,跳出for循环) (a0 != temp) a0=4 4,9,8,10,5,2,7,6,1 i=2: temp=8 j=1 (a1=9 > temp=8) a2=9 4,9,9,10,5,2,7,6,1 j-1=0 j=0 break; (a1 != temp) a1=8 4,8,9,10,5,2,7,6,1 i=3: temp=10 j=2 break j=4: temp=5 .... */

8.二分查找

     基本思想:前提是在已经排好序的数组中,通过将待查找的元素与中间索引值对应的元素进行比较,若大于中间索引值对应的元素,去又半部分查找,,否则,去左半部分查找。,以此类推,直到找到为止,找不到返回一个负数

     算法:

class Test { public static void main(String[] args) { int[] num = {10,20,50,65,88,90}; int index = binarySearch(num,50); System.out.println(index); } public static int binarySearch(int[] num,int key){ int start = 0; int end = num.length-1; while(start<=end){ int middle = (start+end)/2; if(num[middle]>key){ end = middle-1; }else if(num[middle]<key){ start = middle +1; }else{ return middle; } } return -1; } }

五、二维数组 (了解)

1.概念和定义

     二维数组就是关于数组的数组。

     int[][] a = new int[4][]; 的含义?

     目前的对象中只有4个指针,准备指向4个数组。

     

     int[][] a = new int[4][];

     a[0] = new int[3];

     a[1] = new int[3];

     a[2] = new int[3];

     a[3] = new int[3];

     可以简写为:

     int[][] a = new int[4][3];

     

 

2.遍历

     示例代码

class Test { public static void main(String[] args){ int[][] aa = {{1,2,3},{4,5,6},{7,8,9},{11,12,13,14}}; for(int i=0;i<aa.length;i++){ for(int j=0;j<aa[i].length;j++){ System.out.print(aa[i][j]+" "); } System.out.println(); } } }

 

 

 

 

最新回复(0)