一.数组的动态扩容
在课堂上我们已经了解到了数组的动态扩容,我们所用的方法是用一个新的数组来覆盖旧的数组,这当然是一种不错的方式,但是我们给数组进行动态扩容其实有两种方法。
1、新数组覆盖旧数组
当我们需要对数组进行扩容时,可以考虑不扩容数组本身,而是通过定义一个容量更大的数组,然后让原数组名称重新等于大数组即可。由于原数组数据在堆中,失去引用会被 GC 自动回收。示例如下:
public static void main(String[] args) {
int[] arr = {1,3,4}; //定义一个容量为3的数组arr
int[] arr2 =new int[arr.length+1]; //定义一个新数组arr2,容量比arr大1
for(int i=0;i<arr.length;i++){//通过循环给新数组赋值
arr2[i]=arr[i];
}
arr = arr2;//新数组覆盖旧数组
System.out.println(arr.length);//打印结果为4,数组扩容成功
}
我们可以通过定义的新数组arr2的名称直接覆盖掉旧数组arr,原数组被自动回收,从而实现了数组的扩容,因此我们可以根据这个思路进行数组的动态扩容。目标如下:
定义一个容量为1的数组,将系统输入的内容添加到数组中,并每添加一次对数组进行一次扩容。
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int[] arr = new int[1]; //定义一个容量为1的数组arr
int i =0;
while(true) { //通过死循环来观察多次动态扩容的结果
int x = input.nextInt();//接收int类型的输入
arr[i] = x;//将输入传递给数组arr
System.out.println(arr[i]);
int[] arr2 = new int[arr.length + 1]; //定义一个新数组arr2,容量比arr大1
//通过循环对新数组赋值
for(int j=0;j<arr.length;j++){
arr2[j] = arr[j];
}
arr = arr2;//新数组覆盖旧数组
i++;
System.out.println(Arrays.toString(arr));//打印数组内的值
}
}
这是我们已经了解过的方法,那么第二种方法是什么呢?
其实我们也已经遇到过了
2、调用Arrays类实现动态扩容
除了新数组覆盖旧数组的暴力扩容法外,我们还可以通过调用系统自带的java.util.Arrays类中的方法对数组进行动态扩容。Arrays类中实现数组扩容的方法为copyof。(需要导入java.util.Arrays)
copyof方法的扩容原理为使用零复制指定的数组,截断或填充(如有必要),以使副本具有指定的长度,调用格式为Arrays.copyof(原数组名,扩容后的数组大小)。示例如下:
public class ArrayTest {
public static void main(String[] args) {
int[] arr = {1, 3, 4}; //定义一个容量为3的数组arr
arr = Arrays.copyOf(arr,7);//将数组arr扩容到7
arr[6] = 5; //给扩容后的数组下标6定义一个值
System.out.println(Arrays.toString(arr));//打印新数组
}
}
同样我们也使用Arrays类来实现数组的动态扩容,目标如下:
定义一个大小为1的数组,每次输入三个数字,按从大到小的顺序定义到数组中,数组不够的位置通过Arrays类来实现数组的扩容。
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int i = 3;
int[] arr = {1, 3, 4}; //定义一个容量为3的数组arr
while(true) {
System.out.println("请输入三个数字"); //输入要添加的三个数字,分别定义为x1,x2,x3
int x1 = input.nextInt();
int x2 = input.nextInt();
int x3 = input.nextInt();
arr = Arrays.copyOf(arr, arr.length + 3);//将数组arr扩容3,并在扩容的位置分别赋值x1,x2,x3
arr[i] = x1;
arr[i+1] = x2;
arr[i+2] = x3;
i = i + 3;
System.out.println(Arrays.toString(arr));//打印新数组
}
}
通过上面两种方式我们了解了数组的扩容,那么我们还能不能对数组进行其他的一些操作呢?
答案显然是可以的
二、数组的动态删除
其实,数组的动态删除和数组的动态扩容有着异曲同工之妙。都是创建了一个新数组来实现的。
那么具体是怎么操作的呢?
原理:
1.输入一个被删除数组元素的索引值index
2.根据原来数组的长度-1 创建一个新数组;
3.把原来数组的元素进行等索引位置复制到新数组;
4.在复制过程中进行判断,如果 i < index,则直接将 oldarr[i] 复制到新数组;
如果 i >= index ,则将oldarr [ i + 1] 复制到新数组
代码如下:
int[] arr = {11,22,33};
System.out.print("删除前:");
print(arr);
//进行数组的动态删除
arr = remove(arr,1);
System.out.print("删除后:");
print(arr);
/*
动态删除的两个明确:
返回类型:int[]
形参列表:int[] oldArr , int index
*/
public static int[] remove (int[] oldArr , int index ) {
//进行数组的非空校验
if (oldArr == null) {
System.out.println("错误:数组为空");
return oldArr;
}
//进行非法索引校验
if (index < 0 || index >= oldArr.length) {
System.out.println("错误:索引非法");
return oldArr;
}
//根据原来数组的长度创建新数组
int[] newArr = new int[oldArr.length - 1];
//进行数组中元素的复制
for (int i = 0; i < newArr.length; i++) {
if (i < index) {
newArr[i] = oldArr[i];
} else {
newArr[i] = oldArr[i+1];
}
}
return newArr;
}
三、数组的动态插入
这就更不用说了,其本质和前面两种操作没有太大区别,我们就直接来看他是如何实现的吧
原理:
1.输入一个插入数组元素的索引值index
2.根据原来数组的长度 +1 创建一个新数组;
3.把原来数组的元素进行等索引位置复制到新数组;
4.在复制过程中进行判断,如果 i < index,则直接将 oldarr [ i ] 复制到 newarr [ i ];
如果 i >= index ,则将oldarr [ i + 1] 复制到新数组 newarr [ i + 1];
代码如下:
//声明并初始化数组
int[] arr = {11,22,33};
System.out.print("插入前:");
print(arr);
//进行数组的动态插入
arr = insert(arr,2,55);
System.out.print("插入后:");
print(arr);
/*
动态插入的两个明确:
返回类型:int[]
形参列表:int[] oldArr , int index , int num
*/
public static int[] insert (int[] oldArr , int index , int num) {
//进行数组的非空校验
if (oldArr == null) {
System.out.println("错误:数组为空");
return oldArr;
}
//进行非法索引校验
if (index < 0 || index >= oldArr.length) {
System.out.println("错误:索引非法");
return oldArr;
}
//根据原来数组的长度创建新数组
int[] newArr = new int[oldArr.length + 1];
//进行数组中元素的复制
for (int i = 0; i < oldArr.length; i++) {
if (i < index) {
//进行等索引位置复制
newArr[i] = oldArr[i];
} else {
//进行错索引位置复制
newArr[i + 1] = oldArr[i];
}
}
//将待插入元素存储到新数组的指定索引位置
newArr[index] = num;
return newArr;
}