【问题标题】:why does AbstractList.removeRange require quadratic time?为什么 AbstractList.removeRange 需要二次时间?
【发布时间】:2012-08-04 18:18:34
【问题描述】:

我可以在文档中看到:

java.util.AbstractList#removeRange

它需要二次时间:

这个实现得到一个位于fromIndex之前的列表迭代器, 并反复调用 ListIterator.next 后跟 ListIterator.remove 直到整个范围被删除。注意:如果 ListIterator.remove 需要线性时间,这个实现需要二次时间。

但是为什么?代码:

protected void removeRange(int fromIndex, int toIndex) {
        ListIterator<E> it = listIterator(fromIndex);
        for (int i=0, n=toIndex-fromIndex; i<n; i++) {
            it.next();
            it.remove();
        }
    }

对我来说似乎是线性的......但我必须是错的,因为我是这种算法方面的新手。请帮助我理解它。

【问题讨论】:

    标签: java collections big-o time-complexity


    【解决方案1】:

    重要的部分是“注意:如果 ListIterator.remove 需要线性时间,则此实现需要二次时间。” for 循环需要线性时间,你是对的。但是,如果您在每次迭代中执行线性时间步长,则会得到 n * n = n^2。

    【讨论】:

      【解决方案2】:

      原因在:

      it.remove();
      

      这可以是对列表的 O(n) 操作,您可以在 O(n) 循环中调用它。

      换句话说,如果是这样的话,你的真实循环应该是这样的(我编的,但你明白了):

      protected void removeRange(int fromIndex, int toIndex) {
          ListIterator<E> it = listIterator(fromIndex);
          for (int i = 0, n = toIndex - fromIndex; i < n; i++) {
              E item = it.next();
              //it.remove();
              for (int j = ; j < n; j++) {
                  if (list.get(j).equals(e)) {
                      list.remove(e);
                      break;
                  }
              }
          }
      }
      

      【讨论】:

      • “这通常是对列表的 O(n) 操作”“通常”有点夸大其词。 ArrayLists 是 O(n),而 LinkedLists 是 O(1)。
      猜你喜欢
      • 1970-01-01
      • 2014-05-29
      • 2019-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多