java数组

java数组

数组是用于存储多个相同类型数据的存储模型,是相同数据类型的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。

为什么使用数组

如何存储100名学生的成绩?

  • 办法:使用变量存储,重复声明100个double类型变量即可。
  • 缺点:麻烦,重复操作过多。

如何让100名学生成绩全部+1?

  • 办法:100个变量重复相同操作,直至全部完毕。
  • 缺点:无法进行统一的操作。

数组的创建方式

数组的定义格式:
(1)数据类型[] 数组名;2)数据类型 数组名[];
数组名相当于一个引用类型的变量名,它在栈内存中存放的是地址值,这个地址值指向堆内存
举例:
    int[] a;  定义一个int类型的数组a变量
    int a[];  定义一个int类型的a数组变量
注意:这两种定义的效果可以认为是一样的,都是定义一个int类型的数组,但在念法上有些小区别,推荐使用第一种。
   数组定义后,还需要给数组的元素赋值,没有元素值的数组是无法使用的。

数组的初始化

概述:数组的初始化,就是为数组中的元素分配内存空间,并为每一个数组元素赋值。
数组分为动态初始化、静态初始化

1、数组动态初始化

指定数组长度,由系统自行分配初始值之后再赋值,即先分配空间,再进行赋值。
格式:数据类型[] 变量名 = new 数据类型[ 数组长度 ] ;
数组长度其实就是数组中元素的个数

2、数组静态初始化

指定每个数组元素的初始值,由系统决定数组长度
格式:数据类型[] 变量名 = new 数据类型[] {数据1,数据2……};
简化格式: 数据类型[] 变量名 = {数据1,数据2……};

//动态初始化
int a = new int[3];//先分配空间
a[0] = 1;
a[1] = 2;
a[2] = 3;
//静态初始化
int[] b = {1,2,3}//声明的同时直接赋值
M[] m = {new M(),new M()}
/* 
访问数组元素值的格式:
	数组名[索引];
 注意:索引(下标)其实就是数组中每个元素的编号,它从0开始,最大索引是数组长度-1。
 注意:数组的动态初始化和静态初始化不能同时进行,只能任选其一。
*/

在这里插入图片描述

数组常见操作

1)数组遍历

依次输出数组中的每一个元素

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]);
		}
}
     注意:数组提供了一个length的属性,它用于获取数组的长度,其格式如下:
      数组名.length
获取最值

获取数组中的最大值或最小值

/*
实现思路:
	1. 定义max变量,保存数组0索引上的元素
	2. 遍历数组,获取数组中的每个元素
	3. 将遍历到的元素逐一和max变量进行比较
	4. 如果数组元素的值大于max变量的值,将该值保存到max变量
	5. 数组循环遍历结束,max变量保存的就是数组中的最大值
*/
	public static void main(String[] args) {
		int[] arr = { 5, 15, 2000, 10000, 100, 4000 };
		//定义变量,保存数组中0索引的元素
		int max = arr[0];
		//遍历数组,取出每个元素
		for (int i = 0; i < arr.length; i++) {
			//遍历到的元素和变量max比较
			//如果数组元素大于max
			if (arr[i] > max) {
				//max记录住大值
				max = arr[i];
			}
		}
		System.out.println("数组最大值是: " + max);
	}
(3)元素反转

就是把元素前后对调

/*
实现思想:数组最远端的元素互换位置。
	1. 实现反转,就需要将数组最远端元素位置交换
	2. 定义两个变量,保存数组的最小索引和最大索引
	3. 两个索引上的元素交换位置
	4. 最小索引++,最大索引--,再次交换位置
	5. 最小索引超过了最大索引,数组反转操作结束
*/
	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4, 5 };
		/*
		循环中定义变量min=0最小索引
		max=arr.length‐1最大索引
		min++,max‐‐
		*/
		for (int min = 0, max = arr.length ‐ 1; min <= max; min++, max‐‐) {
			//利用第三方变量完成数组中的元素交换
			int temp = arr[min];
			arr[min] = arr[max];
			arr[max] = temp;
		}
		// 反转后,遍历数组
		for (int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}
	}

在这里插入图片描述

(4)查表法

根据键盘录入索引,查找对应元素

(5)数组排序

选择排序

使用下标标记较大或较小的数,都比较完之后再交换两个数

int[] array = {2,5,1,3,6,4,8,9,7};
int count = 0;
for (int i = 0; i < array.length; i++) {
    int index = i;
    for (int j = i; j < array.length; j++) {
        if (array[index] > array[j]) {
            index = j;
        }
    }
    if (index != i) { //找到了比array[i]小的则与array[i]交换位置
        int t = array[i];
        array[i] = array[index];
        array[index] = t;
        count++;
    }
    System.out.print(array.length - 1 > i ? array[i] + ", " : array[i]);
}
System.out.println("\n交换次数:" + count); // 交换7次

冒泡排序

比较两个数的大小,交换两个数

int[] array = {2,5,1,3,6,4,8,9,7};
int count = 0;
for (int i = 0; i < array.length; i++) {
    for (int j = i; j < array.length; j++) {
        if (array[i] > array[j]) {
           int t = array[i];
            array[i] = array[j];
            array[j] = t;
            count++;
        }

    }
    System.out.print(array.length - 1 > i ? array[i] + ", " : array[i]);
}
System.out.println("\n交换次数:" + count); // 交换7次

使用Arrays.sort()排序

  1. 对基本数据类型排序使用优化的快速排序算法
  2. 对引用类型排序使用优化的合并排序算法
public static void main(String[] args){
		int[] nums = new int[]{4,3,5,2,1};
		//借助JDK提供的数组工具,进行排序
		Arrays.sort(nums);
		//第一次遍历(升序)
		for(int i = 0 ; i < nums.length ; i++){
			System.out.println(nums[i]);
		}
		//降序:需要手工的方式完成元素的倒置  5 2 3 4 1
		for(int i = 0 ; i < nums.length / 2 ; i++){// i = 0
			int temp = nums[i];// int temp = 1;
			nums[i] = nums[ nums.length - 1 - i];
			nums[ nums.length - 1 - i] = temp;			
		}		
		//第二次遍历(降序)
		for(int i = 0 ; i < nums.length ; i++){
			System.out.println(nums[i]);
		}			
		//两值交换,借助第三变量
		/*
		int a = 10;
		int b = 20;
		int c = a;//将a中的值保存在c中
		a = b;//将b中的值保存在a中
		b = c;//将c中的值保存在b中
		*/
	}
(6)查找

普通查找

二分查找

(折半检索):先把数组折半,再进行比较,大于中间数则用中间值加一除以二再比较,直至两数相等 注意:要查找的数组必须是有序的,否则查找结果不准确

static int binaryS(int a[], int key) {
    int low = 0;
    int high = a.length - 1;
    while (low <= high) {
        int mid = low + (high - low) / 2;
        if (a[mid] > key)
            high = mid - 1;
        else if (a[mid] < key)
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}
(7)数组作为方法参数

数组作为方法参数传递,传递的参数是数组内存的地址。

public static void main(String[] args) {
	int[] arr = { 1, 3, 5, 7, 9 };
	//调用方法,传递数组
	printArray(arr);
}
	/*
	创建方法,方法接收数组类型的参数
	进行数组的遍历
	*/
public static void printArray(int[] arr) {
	for (int i = 0; i < arr.length; i++) {
		System.out.println(arr[i]);
	}
}

在这里插入图片描述

(8)数组作为方法返回值

数组作为方法的返回值,返回的是数组的内存地址

public static void main(String[] args) {
	//调用方法,接收数组的返回值
	//接收到的是数组的内存地址
	int[] arr = getArray();
	for (int i = 0; i < arr.length; i++) {
		System.out.println(arr[i]);
	}
}
/*
创建方法,返回值是数组类型
return返回数组的地址
*/
public static int[] getArray() {
	int[] arr = { 1, 3, 5, 7, 9 };
	//返回数组的地址,返回到调用者
	return arr;
}

在这里插入图片描述

(9)数组越界异常

原因:访问了数组中不存在的索引时发生

public static void main(String[] args) {
	/*
	创建数组,赋值3个元素,数组的索引就是0,1,2,没有3索引,因此我们不能访问数组中不存在的索引,程序运
	行后,将会抛出 ArrayIndexOutOfBoundsException 数组越界异常。
	*/
	int[] arr = {1,2,3};
	System.out.println(arr[3]);
}
(10)数组空指针异常

原因:数组引用没有指向实体,却在操作实体中的元素时发生

public static void main(String[] args) {
	/*
	arr = null 这行代码,意味着变量arr将不会在保存数组的内存地址,也就不允许再操作数组了,因此运行的时候
会抛出 NullPointerException 空指针异常。
	*/
	int[] arr = {1,2,3};
	arr = null;
	System.out.println(arr[0]);

在这里插入图片描述

数组扩容

数组扩容:本质上就是定义一个新的数组,把原数组的数据复制到新数组,后面填充null
创建数组时,必须显示指定长度,并在创建之后不可更改长度。

扩容的思路:

  • 创建大于原数组长度的新数组。
  • 将原数组中的元素依次复制到新数组中。
  • 将新数组的地址赋值给原数组

在这里插入图片描述

数组复制的方式
  1. for循环
	public static void main(String[] args){
		int[] nums = new int[5];//数组创建之后,长度不可变
		nums[0] = 11;
		nums[1] = 22;
		nums[2] = 33;
		nums[3] = 44;
		nums[4] = 55;
		//1.创建比原数组大的新数组
		int[] newNums = new int[ nums.length * 2 ];
		//2.复制原数组中的所有数据到新数组
		for(int i = 0 ; i < nums.length ; i++){
			newNums[i] = nums[i];
		}
		//遍历原数组
		for(int i = 0 ; i < nums.length ; i++){
			System.out.print( nums[i] +"\t");
		}
		System.out.println();
		//遍历新数组
		for(int i = 0 ; i < newNums.length ; i++){
			System.out.print( newNums[i] +"\t");
		}
	}
  1. 使用System.arraycopy()

System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度)

public static void main(String[] args){
		int[] nums = new int[5];//数组创建之后,长度不可变
		nums[0] = 11;
		nums[1] = 22;
		nums[2] = 33;
		nums[3] = 44;
		nums[4] = 55;
		//复制的赋值
		//1.创建新数组
		int[] newNums = new int[ nums.length * 2 ];
		//2.使用System.arraycopy(原数组,原数组起始下标,新数组,新数组的起始存储下标,需要赋值的个数或长度);
		System.arraycopy( nums , 0 , newNums , 0 , nums.length);
		//遍历新数组
		for(int i = 0 ; i < newNums.length ; i++){
			System.out.print( newNums[i] +"\t");
		}	
	}
  1. 使用Arrays.copyof()

Arrays.copyof(要复制的数组,复制长度),返回带有原值的新数组

public static void main(String[] args){
		int[] nums = new int[5];//数组创建之后,长度不可变	
		nums[0] = 11;
		nums[1] = 22;
		nums[2] = 33;
		nums[3] = 44;
		nums[4] = 55;
		//1.创建新数组、复制元素
		int[] newNums = java.util.Arrays.copyOf(nums , nums.length * 2);//将带有原值的新数组返回给我们
		//2.遍历
		for(int i = 0 ; i < newNums.length ; i++){
			System.out.print( newNums[i] +"\t");
		}
	}
地址替换
  • 数组作为引用类型之一,其变量中存储的是数组的地址。
  • 完成元素复制后,需将新数组地址,赋值给原变量进行替换。
public static void main(String[] args){
		int[] nums = new int[5];//数组创建之后,长度不可变
		nums[0] = 11;
		nums[1] = 22;
		nums[2] = 33;
		nums[3] = 44;
		nums[4] = 55;
		//复制的赋值
		//1.创建新数组
		int[] newNums = new int[ nums.length * 2 ];
		//2.使用System.arraycopy(原数组,原数组起始下标,新数组,新数组的起始存储下标,需要赋值的个数或长度);
		System.arraycopy( nums , 0 , newNums , 0 , nums.length);
		//遍历新数组
		for(int i = 0 ; i < newNums.length ; i++){
			System.out.print( newNums[i] +"\t");
		}	
		//将新数组地址赋值给原数组,实现数组扩容
		nums = newNums;
	}

在这里插入图片描述

Arrays.copyof()与System.arraycopy()的区别:
  1. 写法区别:
  • Arrays.copyof(要复制的数组,复制长度),底层由System.arraycopy()实现
  • System.arraycopy(要复制的数组,起始位置,复制到哪个数组,起始位置,复制长度)
  1. 数组个数​:
  • Arrays.copyof()只要调用该方法就会创建新的数组,无需手动创建
  • System.arraycopy()不会创建新的数组,可以复制到原数组上,有需要时,要先创建一个新数组
数组内存图
一个数组内存图
public static void main(String[] args) {
	int[] arr = new int[3];
	System.out.println(arr);//[I@5f150435
}

在这里插入图片描述

两个数组内存图
public static void main(String[] args) {
	int[] arr = new int[3];
	int[] arr2 = new int[2];
	System.out.println(arr);
	System.out.println(arr2);
}

在这里插入图片描述

两个变量指向一个数组
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]);
}

在这里插入图片描述

数组的三个基本特点

  1. 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
  2. 其元素必须是相同类型,不允许出现混合类型。
  3. 数组类型可以是任何数据类型,包括基本类型和引用类型。

数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。

稀疏数组

只记录原始数组有几行几列、有多少个有效值
当一个数组中大部分都是0或者同一个值的时候,可以用稀疏数组来保存

在这里插入图片描述

二维数组

概述:二维数组其实就是一个里面存储的元素为一维数组的数组。即数组中存储的元素还是数组
在这里插入图片描述

声明方式

(1)数组类型[][] 数组名 = new 数组类型[m][n];

// 声明方式与一维数组相似
数组类型[][] 数组名 = new 数组类型[m][n];
// m表示这个二维数组有多少个一维数组,n表示每个一维数组的元素个数
int[][] i = new int[3][2];
// 创建了一个数组,长度为3,每个位置存储了一个数组,每个位置存储的数组长度都是2
// 即:总共创建了四个数组,一个数组里面存储了三个长度为2的数组,注意:这里所说的都是数组的地址,即存储的是子数组的地址

以下格式也可以定义一个二维数组,但不推荐:
	    数据类型 数组名[][] = new 数据类型[m][n];
	    数据类型[] 数组名[] = new 数据类型[m][n];

在这里插入图片描述
(2)数据类型[][] 数组名 = new 数据类型[m][];

// 只定义外围数组的长度,每个位置的一维数组的长度未知
	数据类型[][] 数组名 = new 数据类型[m][];
// 外围数组第一个位置存储了一个长度为n1的一维数组
     数组名[0] = new 数据类型[n1];
// 外围数组第二个位置存储了一个长度为n2的一维数组
     数组名[1] = new 数据类型[n2];
// 注意:n1和n2可以不相等
     ...

     数组名[m-1] = new 数据类型[nm];

    说明:
	m表示这个二维数组有多少个一维数组
	第二种格式没有直接给出一维数组的元素个数,这时可以动态地给一维数组分配内存空间

(3)数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2…},{元素1,元素2…},{元素1,元素2…}…};

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

	数据类型[][] 数组名 = {{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}...};

访问二维数组元素值的格式:

数组名[m][n];

说明:表示访问第m+1个一维数组的第n+1个元素
二维数组的内存分配

高维数组中的每一个元素,保存了低维数组的地址。访问array[0]等价于在访问0x0000A111。
在这里插入图片描述

二维数组的操作

(1)二维数组遍历:外循环控制二维数组的长度,也就是一维数组的个数;内循环控制一维数组的长度。

public static void main(String[] args){
		
		int[][] nums = new int[3][5];
		
		nums[0][0] = 10;//第一行,第一列
		nums[0][3] = 20;//第一行,第四列
		nums[1][0] = 30;//第二行,第一列
		nums[1][1] = 40;//第二行,第二列
		nums[2][2] = 50;//第三行,第三列
		nums[2][4] = 60;//第三行,第五列
		
		
		for(int i = 0 ; i < nums.length ; i++){ //外层控制行数
			
			for(int j = 0 ; j < nums[i].length ; j++){ // j = 1 内层控制列数
				
				System.out.print( nums[i][j] +"\t");
				
			}
			System.out.println();
			
		}

		System.out.println( nums.length );//nums变量中,所持有的地址对应的数组长度是多少 = 3

		System.out.println( nums[0].length );// nums[0],高位数组中的第一个元素所指向的低维数组的长度
		
		
		System.out.println( nums[0] ); // 长度5    先创建了长度为5的低维数组,将地址赋值给高维空间
		System.out.println( nums[1] );
		System.out.println( nums[2] );
		

	}

(2)二维数组求和
(3)打印杨辉三角

public static void main(String[] args){
		
		//####1#
		//###1#1
		//##1#0#1
		//#1#0#0#1
		//1#0#0#0#1
		
		int rows = 7;
		
		int[][] yh = new int[rows][];

		//创建多个不同长度的二维数组
		for(int i = 0 ; i < rows ; i++){
			yh[i] = new int[i+1];
		}
		
		//完成初始值的赋值(每行的首位都是1)
		for(int i = 0 ; i < yh.length ; i++){ // i = 2
			yh[i][0] = 1;
			yh[i][i] = 1;
		}
		
		//计算
		for(int i = 2 ; i < yh.length ; i++){
			for(int j = 1 ; j < i ; j++){
				//当前位置的值 = 上一行的同列 + 上一行的前一个列
				yh[i][j] = yh[i-1][j] + yh[i-1][j-1];
			}
		}

		for(int i = 0 ; i < yh.length ; i++){
			
			for(int j = rows - 1 ; j > i ; j--){//满足4次
				System.out.print("\t");
			}
			
			
			for(int j = 0 ; j < yh[i].length ; j++){
				System.out.print( "\t"+ yh[i][j] +"\t");
			}
			System.out.println();
			
		}
		
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值