【问题标题】:Arraylist time complexity: do you copy over and shift elements as needed at the same time?Arraylist 时间复杂度:您是否同时根据需要复制和移动元素?
【发布时间】:2015-09-15 23:24:52
【问题描述】:

我正在尝试找出这两种方法在时间复杂度上的区别:

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 是根据最坏情况定义的,添加到数组列表的最坏情况涉及调整大小,从而将所有元素复制到新数组中。我认为方法 2 将是 O(n^2) 因为对于数组中的每个元素,您可能必须将所有元素复制到一个更大的数组中。

但我不确定方法 1,因为我不确定事情的完成顺序。似乎可以组合复制元素和插入新元素,这样您就不必先将旧元素添加到更大的列表中,然后在添加新元素时根据需要移动所有元素。如果是这样的话,方法 1 似乎是 O(n^2) 而不是 O(n^3)。但这就是它的工作原理吗?

【问题讨论】:

    标签: java arraylist time-complexity add


    【解决方案1】:

    ArrayList 由数组支持。如果在数组的头部“插入”一个元素,则必须将所有其他元素向右移动一个以腾出空间。这意味着一次调用:

    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)

    【讨论】:

    • 这非常有用。谢谢!
    【解决方案2】:

    方法一是O(n^2)

    方法2比O(n^2)要好得多:存储数据的内部数组分配了一些空闲空间,内部数组增长呈指数增长,因此n个元素的迭代很少发生。由于您在最后追加,因此没有其他理由在每一步迭代所有元素。

    【讨论】:

    • 我对最坏的情况如何运作感到有些困惑。很少,但有时,方法 2 会是 O(n^2),不是吗?这些不常见的事件不构成整个算法的大问题吗?方法2是简单的O(n)吗?
    • 是的,方法 2 是 O(n) - 一个很好的解释在这里:stackoverflow.com/questions/200384/constant-amortized-time
    猜你喜欢
    • 1970-01-01
    • 2011-09-26
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 2019-06-16
    • 1970-01-01
    相关资源
    最近更新 更多