11.数组

数组

数组的定义

数组是一个数据容器,可以存储基本数据类型,也可以存储引用数据类型的数据;数组的长度是不可变的,数组的内存空间是连续的;一个数组一旦实例化完成,长度是不能够改变的。

数组的声明

int[] arr1 = new int[5];//java语言风格
int arr2[] = new int[5];//C系语言风格

int[] arr3 = new int[] {1,2,3,4,5}
int[] arr4 = {1,2,3,4,5}

数组引用

数组的实例化的时候, 需要使用到关键字new.
数组, 其实是在堆上开辟的连续的空间。 例如 new int[5] , 就是在堆上开辟5个连续的4字节空间。
然后, 将堆上的内存地址, 赋值给栈上的变量array(引用)。
在这里插入图片描述

  • 内存地址扩展说明
    在这里插入图片描述
    关于数组中地址和值的说明:
  1. 引用地址(包括数组地址),是一个十六进制的数。
  2. 在内存的堆中,是连续的空间,上图中的数组中一共5个元素,每一个4个字节,数组的每个元素都有自己的地址,我们得到第一个后,根据元素所占内存可以推算出后面的地址。
  3. 数组第一个元素比较特殊,它的地址同时还是整个数组的地址

数组的下标

下标:就是数组中的元素在数组中存储的位置索引。
注意:数组的下标是从0开始的, 即数组中的元素下标范围是 [0, 数组.length - 1]
通过下标进行数组元素访问

public class Test {
	public static void main(String[] args) {
	// 实例化一个数组
	int[] array = { 1, 2, 3, 4, 5 };
	// 访问数组中的元素
	array[2] = 300; // 将数组中的第2个元素修改成300, 此时
	数组中的元素是 [ 1, 2, 300, 4, 5 ]
	System.out.println(array[2]); // 获取数组中的第2个元素, 此时的输出结果是 300
	}
}
  • 注意:在访问数组中的元素的时候, 注意下标的问题,使用错误的下标访问数组中的元素, 将会出现 ArrayIndexOutOfBoundsException异常

通过增强for循环进行数组元素访问

public class Test {
public static void main(String[] args) {
	// 实例化一个数组
	int[] array = { 1, 2, 3, 4, 5 };
	// 依次使用数组中的每一个元素, 给迭代变量进行赋值。
	// 此时, 数组中的每一个元素依次给 element 进行赋值。
	for (int element : array) {
	System.out.println(element);
	}
	}
}

两种遍历方式的对比:

  • 如果需要在遍历的同时, 获取到数组中的元素下标, 需要使用下标遍历法。
  • 如果需要在遍历的同时, 修改数组中的元素, 需要使用下标遍历法。
  • 如果仅仅是想要获取数组中的每一个元素, 不需要下标, 也不需要修改数组中的元素,使用增强for循环。 因为这种方式, 遍历的效率比下标遍历法高。

函数和数组的联合应用

函数传参分类

  • 值传递:将保存简单数据的变量作为参数传递
  • 址传递:将保存地址的变量作为参数传递
  • 址传递优点:让我们可以实现使用一个变量一次传递多个值
public class Demo3 {
	public static void main(String[] args) {
			//求三个数的和
			//直接用数值作为参数传递-值传递
			int tmp1 = getMax(3, 4, 6);
			System.out.println(tmp1);
			//用数组实现求三个数的和-址传递
			int[] arr1 = new int[] {3,5,8};
			int tmp2 = getMax(arr1);
			System.out.println(tmp2);
		}
		public static int getMax(int a,int b,int c) {//值传递
			int tmp = a>b?a:b;
			return c>tmp?c:tmp;
		}
		public static int getMax(int[] arr) {//地址传递 arr = arr1
			int max = arr[0];
			for (int i=0;i<arr.length-1;i++) {
			if (max < arr[i+1]) {
			max = arr[i+1];
			}
		}
		return max;
	}
}

值传递和址传递比较
通过值作为参数传递,函数内部值的变化不会改变外部的值。
通过地址作为参数传递,函数内部值的变化可以直接改变外部值。

public class Demo4 {
	public static void main(String[] args) {
		//交换两个数的值
		int[] temp = {3,5};
		//地址传递
		jiaohuan1(temp);
		//我们发现通过址传递数组temp内的两个值发生了交换
		System.out.println("temp[0]:"+temp[0]+" temp[1]:"+temp[1]);// 5
		3
		//值传递
		int[] temp1 = {3,5};
		jiaohuan2(temp1[0], temp1[1]);
		//通过值传递数组temp内的两个值没有发生交换
		System.out.println("temp1[0]:"+temp1[0]+"
		temp1[1]:"+temp1[1]);// 3 5
	}
	//地址传递
	public static void jiaohuan1(int[] arr) {
		arr[0] = arr[0] ^ arr[1];
		arr[1] = arr[0] ^ arr[1];
		arr[0] = arr[0] ^ arr[1];
	}
	//值传递
	public static void jiaohuan2(int a,int b) {
		a = a ^ b;
		b = a ^ b;
		a = a ^ b;
	}
}

总结:址传递的最终原因是两个变量保存了同一个数组的地址,操作的是同一个数组。

可变长参数

概念:
可以接收多个类型相同的实参,个数不限,使用方式与数组相同。
在调用方法的时候, 实参的数量可以写任意多个。
作用:简化代码,简化操作等
语法:

// 这里的参数paramters其实就是一个数组
static void show(int... parameters) {
	//
}

例子:

public static int sum1(int... a){
	int sum=0;
	for (int i = 0; i < a.length; i++) {
		sum+=a[i];
	}
	return sum;
}

数组的排序

冒泡排序

//BubbleSort
public static void bubble(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        boolean flag = true;
        for (int j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j+1]) {//升序
                //使用位异或交换
                arr[j] ^= arr[j+1];
                arr[j+1] ^= arr[j];
                arr[j] ^= arr[j+1];
                flag = false;
            }
        }
        if (flag) {
            break;
        }
    }
}

选择排序

//SelectedSort
public static void selectedSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
            if (arr[minIndex] > arr[j]) {
                minIndex = j;
            }
        }
        if (minIndex != i ){
            arr[i] ^= arr[minIndex];
            arr[minIndex] ^= arr[i];
            arr[i] ^= arr[minIndex];
        }
    }
}

数组的查询

线性查询

顺序查询, 即遍历数组中的每一个元素, 和要查询的元素进行对比。 如果是要查询的元素,这个下标就是要查询的下标。
查询三要素:

  1. 我们只找查到的第一个与key相同的元素,查询结束。
  2. 当查询到与key相同的元素时,返回元素的下标。
  3. 如果没有查询到与key相同的元素,返回-1。
//LinerSearch
public static int linerSearch(int[] arr, int number) {
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == number) {
            return i;
        }
    }
    return -1;
}

二分查询

注: 使用二分查询的前提是,待查询的数组必须是有序的
二分查询: 即利用数组中间的位置, 将数组分为前后两个字表。 如果中间位置记录的关键字
大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到
找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

//BinarySearch
public static int binarySearch(int[] arr, int number, int left, int right) {
    if (left > right) {
        return -1;
    }
    int mid = (left + right) / 2;

    if (arr[mid] > number) {
        return binarySearch(arr, number, left, mid-1);
    } else if (arr[mid] < number) {
        return binarySearch(arr, number, mid+1, right);
    } else {
        return mid;
    }
}

二维数组

定义:
二维数组, 其实就是数组中嵌套数组。也就是二维数组中的每一个元素都是一个小的数组。理论上来讲, 还可以有三维数组、四维数组, 但是常用的其实就是二维数组。
定义和使用:

public class Array1 {
    public static void main(String[] args) {
        int[] arr = new int[3];
        // 1. 实例化一个二维数组
        // 第一个中括号中的3: 二维数组中包含了三个一维数组
        // 第二个中括号中的5: 二维数组中的每一个一维数组长度为5
        int[][] array1 = new int[3][5];
        // 使用双下标访问数组中的元素
        array1[0][3] = 10;
        // 这里得到的,是二维数组的长度,3
        System.out.println(array1.length);
        // 2. 实例化一个二维数组
        // 第一个中括号中的3: 二维数组中包含了三个一维数组
        // 第二个中括号中什么都没有,代表现在二维数组中的三个元素是 null
        int[][] array2 = new int[3][];
        array2[0] = new int[] { 1, 2, 3 };
        // 3. 通过初始值实例化一个二维数组
        int[][] array3 = { {1, 2, 3}, {1, 2, 3, 4, 5}, {2, 3, 4} };
        // 4. 二维数组的遍历
        for (int i = 0; i < array3.length; i++) {
            for (int j = 0; j < array3[i].length; j++) {
                System.out.print(array3[i][j] + " ");
            }
        }
    }
}

(补充)常用的数组工具类Arrays

方法描述
copyOf(int[] array, int newLength)从原数组中拷贝指定数量的元素,到一个新的数组中,并返回这个新的数组
copyOfRange(int[] array, int from, int to)从原数组中拷贝指定范围 [from, to) 的元素,到一个新的数组中,并返回这个新的数组
equals(int[] array1, int[] array2)判断两个数组是否相同
fill(int[] array, int element)使用指定的数据,填充数组
sort(int[] array)对数组进行排序(升序)
binarySearch(int[] array, int element)使用二分查找法,到数组中查询指定的元素出现的下标
toString(int[] array)将数组中的元素拼接成字符串返回
  • 测试代码
import java.util.Arrays;

public class ArraysUse {
    // Arrays 工具方法: 可以便捷的实现指定操作的方法
    // Arrays 工具类: 若干个工具方法的集合
    public static void main(String[] args) {
        // 1. 实例化一个数组
        int[] array = { 1, 3, 5, 7, 9, 0, 8, 6, 4, 2 };
        // 从原数组中拷贝指定数量的元素,到一个新的数组中,并返回这个新的数组
        // 第一个参数:源数组
        // 第二个参数:需要拷贝的元素数量,如果这个数量比源数组长,目标数组剩余的部分补默认值
        int[] ret1 = Arrays.copyOf(array, 13);
        // 从原数组中拷贝指定范围 [from, to) 的元素,到一个新的数组中,并返回这个新的数组
        // 第一个参数:源数组
        // 第二个参数:起始下标,从这个下标位的元素开始拷贝
        // 第三个参数:目标下标,拷贝到这个下标位截止
        int[] ret2 = Arrays.copyOfRange(array, array.length, array.length + 10);
        // 判断两个数组是否相同
        // 判断的逻辑:长度、每一个元素依次都相等
        boolean ret3 = Arrays.equals(ret1, ret2);
        // 使用指定的数据,填充数组
        // 第一个参数:需要填充的数组
        // 第二个参数:填充的数据
        Arrays.fill(ret2, 100);
        // 对数组进行排序(升序)
        Arrays.sort(array);
        // 使用二分查找法,到数组中查询指定的元素出现的下标
        // 第一个参数:需要查询的数组
        // 第二个参数:需要查询的数据
        // 返回:这个元素出现的下标,如果不存在,返回-1
        int index = Arrays.binarySearch(array, 4);
        // 将数组中的元素拼接成字符串返回
        String str = Arrays.toString(array);
        System.out.println(str);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值