我试图找出这两种方法之间时间复杂度的差异:
public ArrayList<Integer> populateList(int n){
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i=0; i< n; i++)
list.add(0, i);
return list;
}
public ArrayList<Integer> populateList(int n){
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i=0; i< n; i++)
list.add(i);
return list;
}
据我所知,big-o是根据最坏情况定义的,最糟糕的情况是添加到arraylist包括调整大小,从而将所有元素复制到一个新数组中。我认为方法2将是O(n ^ 2),因为对于数组中的每个元素,您可能必须将所有元素复制到更大的数组中。
但我不确定方法1,因为我不确定事情的顺序。似乎复制元素和插入新元素可以组合在一起,这样您就不必首先将旧元素添加到更大的列表中,然后在添加新元素时根据需要移动所有元素。如果是这种情况,似乎方法1是O(n ^ 2)而不是O(n ^ 3)。但这是怎么回事?
答案 0 :(得分:1)
ArrayList
由数组支持。如果你&#34;插入&#34;在数组头部的元素,你必须将所有其他元素向右移动一个以腾出空间。这意味着单次调用:
list.add(0, i);
是O(n)
,因为必须移动每个元素(已添加)
如果您n
次执行此操作,则O(n^2)
。
但是在(支持)数组的末尾添加一个元素:
list.add(i);
只需要在数组的未使用元素中放置一个值,即O(1)
,除非数组已满,另一个更大的数组需要分配和复制到O(n)
,但是随着阵列的增长,频率不断下降,特别是O(log n)
。
如果您执行O(1)
的操作,O(n)
除了log n
次n
次,O(n log n)
次,sex
。
答案 1 :(得分:0)
方法1是O(n ^ 2)
方法2比O(n ^ 2)好得多:存储数据的内部数组分配有一些自由空间,内部数组增长是指数级的,因此n个元素的迭代很少发生。由于您最后追加,因此没有其他理由在每一步迭代所有元素。