可变容量数组
算法原码
/**
* 可变容量数组, 暂时只存数字
* 实现了动态数组的扩容方法
* 可以单个单个add的添加元素, 也可以把一整个数组元素addAll添加进去
* size()获取元素数量, get()获取指定索引的元素
* @author hui an
* */
public class VariableCapacityArray {
/**
* 默认初始容量
* */
private static final int DEFAULT_CAPACITY = 10;
/**
* 默认初始数组
* */
private int[] nums = new int[DEFAULT_CAPACITY];
/**
* 旧数组容量
* */
private int oldCapacity = nums.length;
/**
* 元素数量
* */
private int size = 0;
/**
* 无参构造
* */
public VariableCapacityArray() {
}
/**
* 1. 指定容量进行构造
* */
public VariableCapacityArray(int capacity) {
if (capacity < 10) {
throw new RuntimeException("指定容量必须大于10");
}
this.oldCapacity = capacity; //将容量赋值给未扩容容量属性
nums = new int[oldCapacity]; //为数组指定容量
}
/**
* 单个单个元素进行添加
* */
public void add(int num) {
int tempCapacity = 0; //添加单个元素,临时容量设为0
judgeCapacity(tempCapacity); //执行扩容
nums[size] = num; //将元素添加到数组末位
size++; //数组元素个数加1
}
/**
* 通过数组添加多个元素
* */
public void addAll(int[] addArray) {
int tempCapacity = addArray.length; //添加多个元素,临时容量设为数组长度
judgeCapacity(tempCapacity); //扩容
for (int i = 0; i < addArray.length; i++) {
add(addArray[i]); //向扩容后的数组依次填入新值
}
}
/**
* 获取指定索引位置的元素
* */
public int get(int index) {
if (size - 1 < index) {
throw new RuntimeException("索引超过当前存储的元素总量");
} else if (index < 0) {
throw new RuntimeException("索引不能小于0");
}
return nums[index];
}
/**
* 获取元素数量
* */
public int size() {
return size;
}
/**
* 2. 动态扩容
* */
private void judgeCapacity(int tempCapacity) { //传入临时容量
int newCapacity = tempCapacity;
if (size + newCapacity > oldCapacity - 1) {
/*
size表示当前元素数量,newCapacity表示新增的元素数量。如果二者相加多于数组容量,执行扩容操作。
这里的-1作用是为了确保数组元素数量达到数组容量上限时,不触发扩容,只有在超出容量上限时才会扩容。
新增单个元素时,newCapacity值为0
例如:不加-1,如果当前数组长度为10,元素数量为10,再新增一个元素时,实际上应该扩容。但是10>10结果是false,就不会执行扩容操作。
这种情况在不是临界值,比如数组长度为10,元素数量为9时并不会暴露出来。但是一到临界值,该问题就会导致数组下标越界异常。所以
-1的作用就是为了避免这个异常。
除了此之外,你可以使用 >=。但要注意,大多数情况下,使用 > 更为常见,避免了在容量刚好等于元素数量时就进行扩容的情况。
*/
newCapacity = oldCapacity+oldCapacity >> 1; //将新数组容量扩大为旧数组1.5倍。使用移位运算符优化内存。
if (newCapacity < tempCapacity) {
/*
当传入巨量数据,可能一次扩1.5倍还是不够用。你可能会想,那我再加个判断,扩一次1.5倍不够那就多扩容几次。直到扩容够了为止。这种方式可以使用
循环+判断实现。但是我们要考虑一个性能问题,当传入巨量数据时,这种循环肯定要执行很多次,这是非常消耗系统资源的。所以出于性能考虑,我们直接
一步到位,将旧数组直接扩容到能刚好接收这些数据的程度。
*/
newCapacity = tempCapacity + oldCapacity;
}
oldCapacity = newCapacity; //将新数组容量赋给原数组。便于循环
nums = Arrays.copyOf(nums, newCapacity);
}
}
/**
* 重写toString方法, 可直接进行打印输出控制台
* */
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++) {
sb.append(nums[i]);
if (i == size - 1) {
sb.append("]");
break;
}
sb.append(", ");
}
return sb.toString();
}
/**
* 重写equals方法, 可进行内容比较
* */
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (obj instanceof VariableCapacityArray) {
VariableCapacityArray array = (VariableCapacityArray) obj;
if (array.size != size) {
return false;
}
for (int i = 0; i < array.size; i++) {
if (array.get(i) != nums[i]) {
return false;
}
}
return true;
}
return false;
}
/**
* 重写hashCode方法
* */
@Override
public int hashCode() {
return size + oldCapacity + Arrays.hashCode(nums);
}
}
使用方法
可变容量数组类的主要功能和用法如下:
构造函数
VariableCapacityArray():无参构造函数,创建一个默认容量的可变容量数组实例。
VariableCapacityArray(int capacity):带初始容量参数的构造函数,创建一个指定初始容量的可变容量数组实例。
添加元素
void add(int num):向数组中添加单个元素。
void addAll(int[] addArray):通过数组添加多个元素。
获取元素
int get(int index):获取指定索引位置的元素。
其他方法
int size():获取数组中的元素数量。
String toString():重写的 toString 方法,返回数组的字符串表示。
boolean equals(Object obj):重写的 equals 方法,用于比较两个数组是否内容相同。
int hashCode():重写的 hashCode 方法,返回数组的哈希码。
原理与实现思路
可变容量数组的实现基于以下原理和实现思路:
-
初始数组和容量:在构造函数中创建固定大小的初始数组,并维护 size 和 oldCapacity 两个关键变量。
-
动态扩容:当添加元素时,判断当前有效元素数量是否达到容量上限。如果是,触发动态扩容操作,创建更大容量的新数组,将旧数组中的元素复制到新数组中。
-
重写方法:为了提供更好的用户体验,重写了 toString、equals 和 hashCode 方法,使其更易于打印、比较和哈希操作。
-
数组访问和元素获取:实现通过索引访问数组中的元素,确保索引的有效性。
示例
以下是一个示例代码,演示了可变容量数组的使用:
public class ExampleUsage {
public static void main(String[] args) {
VariableCapacityArray array = new VariableCapacityArray(15);
array.add(10);
array.add(20);
array.addAll(new int[]{30, 40, 50});
System.out.println("Array: " + array); // 打印数组内容
int element = array.get(2);
System.out.println("Element at index 2: " + element);
int size = array.size();
System.out.println("Array size: " + size);
VariableCapacityArray array2 = new VariableCapacityArray(15);
array2.add(10);
array2.add(20);
array2.addAll(new int[]{30, 40, 50});
System.out.println("Array are equal: " + array.equals(array2)); // 比较两个数组内容是否相同
}
}
y2 = new VariableCapacityArray(15);
array2.add(10);
array2.add(20);
array2.addAll(new int[]{30, 40, 50});
System.out.println("Array are equal: " + array.equals(array2)); // 比较两个数组内容是否相同
}
}