因此,当数组无法保存我们想要的信息量时,通常的编程习惯是将数组的大小加倍。我们这样做是通过创建一个新数组,使用原始数组大小的两倍,用旧值填充这个新数组,并将其设置为旧数组。 这是Java中的一个例子:
public int[] doubleArray(int[] old) {
int[] doubled = new int[old.length * 2];
for (int i = 0; i < old.length; i++) {
doubled[i] = old[i];
}
return doubled;
}
因此,使用标准数组并在需要时加倍大小或简单地使用ArrayList(根据您给出的输入改变自己的大小1),更多更好 ?基本上,当您需要存储多于数组允许的数量时,将数组大小加倍是否更好,或者每次增加其大小为1?一个人成为比另一个更好的选择的限制是什么?
如果我不得不猜测,使用标准数组应该更快,因为它在java.lang
中,所以我做了下面的课来测试我的理论:
public class ArrayTesting {
public static void main(String[] args) {
long startTime1 = System.nanoTime();
int[] ints = new int[10];
for (int i = 0; i < ints.length; i++) {
ints[i] = i * 2;
}
long timeToSetOriginalValues = (System.nanoTime() - startTime1);
long startTime2 = System.nanoTime();
ints = doubleArray(ints);
long timeToDouble = (System.nanoTime() - startTime2);
long startTime3 = System.nanoTime();
for (int i = 9; i < ints.length; i++) {
ints[i] = i * 2;
}
long timeToSetNewValues = (System.nanoTime() - startTime3);
System.out.println("Set Values in " + timeToSetOriginalValues);
System.out.println("Doubled Array in " + timeToDouble);
System.out.println("Finished setting values in " + timeToSetNewValues);
System.out.println("Total time: " + (timeToSetOriginalValues + timeToDouble + timeToSetNewValues));
}
public static int[] doubleArray(int[] old) {
int[] doubled = new int[old.length * 2];
for (int i = 0; i < old.length; i++) {
doubled[i] = old[i];
}
return doubled;
}
}
但由于一个未知的原因,我的结果变得非常不同。从11,000到4,000之间的所有时间变化的总时间。假设这是我做错的事情,是否有人能更好地回答我的问题?
答案 0 :(得分:1)
对,我调查了一下,结果如下:
我创建了一个新类来测试编辑数组的时间,以及编辑ArrayList的时间。让我们从ArrayTesting类开始。
public class ArrayTesting {
private static long totalTotal = 0L;
private static int[] ints = new int[10];
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
runTest();
}
System.out.println("Final Length of Array: " + ints.length);
System.out.println("Total Time was: " + totalTotal);
}
private static void runTest() {
long startTime = System.nanoTime();
for (int i = 0; i < ints.length; i++) {
ints[i] = i * 2;
}
ints = doubleArray(ints);
for (int i = 9; i < ints.length; i++) {
ints[i] = i * 2;
}
long testTime = System.nanoTime() - startTime;
totalTotal = totalTotal + testTime;
}
private static int[] doubleArray(int[] old) {
int[] doubled = new int[old.length * 2];
for (int i = 0; i < old.length; i++) {
doubled[i] = old[i];
}
return doubled;
}
}
此课程的流程如下:
创建新的整数对象数组(是的,这很重要),长度为10。
对于五次迭代,将当前数组的所有索引设置为index * 2
,然后将数组大小加倍,并使用各自的值index * 2
填充新索引。
打印结果
按照相同的过程,我为ArrayList创建了一个测试类:
import java.util.ArrayList;
class ArrayListTester {
public static ArrayList<Integer> arl = new ArrayList<Integer>();
public static long totalTotal = 0L;
public static void main(String[] args) {
//Set initial size for ArrayList to 10
while(arl.size() < 10) arl.add(0);
//Setting the size was not timed.
for (int i = 0; i < 5; i++) {
runTest();
}
System.out.println("Total ArrayList size: " + arl.size());
System.out.println("Total Time: " + totalTotal);
}
public static void runTest() {
long startTime1 = System.nanoTime();
int initialSize = arl.size();
for (int i = 0; i < initialSize * 2; i++) {
if (i < initialSize)
arl.set(i, ((Integer) i * 2));
else
arl.add((Integer) i * 2);
}
long totalForRun = System.nanoTime() - startTime1;
totalTotal = totalTotal + totalForRun;
}
}
如果您通读了这个类,您确实会发现它遵循相同的步骤,但是使用ArrayList可以使代码更加简洁。
现在让我们来看看我们的结果......
由于每个类在5次迭代中运行倍增大小的事物,因此我们最后的数组大小为320或10 * (2 ^ 5)
(注意两个数组的起始大小为10)。但是,经过几次快速测试后,时间消耗就大不相同了。
现在,连续5次运行ArrayTester类,并计算每次运行的平均时间(将其相加并除以运行次数),我收到的平均值为468,290纳秒,有些人可能会认为这是简单地将数组加倍是一个相当不错的组块,但只是等待......
接下来,移动到ArrayListTester类并运行它5次以获得平均值,我收到的平均值恰好是2,069,230纳秒。
如果您想亲自测试这些数字,我会在在线编译/解释器here上运行这些程序。
最终结果:完成同一任务所需的ArrayList几乎长了4.5倍。
现在回到最初提出的问题: &#34; 所以更好使用标准数组并在需要时加倍,或者只使用ArrayList?&#34;
答案真正涉及您希望代码的效率。对于ArrayList,效率字面上不再存在,但代码的美学和组织显着增加。另一方面,如果您正在寻找一种更有效的处理方法,并且不关心您需要编写的代码,那么请使用数组。
答案 1 :(得分:0)
如果你看一下ArrayList
实现,即使它有Array
对象,当你调用add
方法时,它也会确保容量,如果需要,增加大小像
elementData = Arrays.copyOf(elementData, newCapacity);
其中elementData
是存储数据的内部数组。
关于性能或内存消耗,因为它是具有许多功能的包装器,显然会与Array
对象进行一些成本比较。
答案 2 :(得分:0)
简单的Array
总是会更快,因为ArrayList
是一个Array
,当它在空间不足时创建一个新的Array
,并在它到达时缩小它大。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
代码取自OpenJDK7,您可以清楚地看到,简单的add
方法所需的开销很小,即检查array
的大小,如果它是小的还是大的,将array
复制到更大的数组,然后设置元素。正常Array
就可以了。
Arr[index] = value;
但是ArrayLists
功能的增加以及代码质量的提升,在大多数非性能优化方案中都会远远优于传统的Array
。
作为研究,您可以在http://algs4.cs.princeton.edu/home/找到已经很好实施的Arrays
调整大小的示例,其中包含调整大小Array
http://algs4.cs.princeton.edu/13stacks/ResizingArrayStack.java.html的示例。