提交 7d418498 编写于 作者: W wizardforcel

ch3.

上级 b3318859
......@@ -144,3 +144,23 @@ public boolean add(E element) {
这种划分算法的方式,通过计算一系列调用中的平均时间,称为摊销分析。你可以在 <http://thinkdast.com/amort> 上阅读更多信息。重要的想法是,复制数组的额外成本是通过一系列调用展开或“摊销”的。
现在,如果`add(E)`是常数时间,那么`add(int, E)`呢?调用`add(E)`后,它遍历数组的一部分并移动元素。这个循环是线性的,除了在列表末尾添加的特殊情况中。因此, `add(int, E)`是线性的。
## 3.3 问题规模
最后一个例子中,我们将考虑`removeAll`,这里是`MyArrayList`中的实现:
```java
public boolean removeAll(Collection<?> collection) {
boolean flag = true;
for (Object obj: collection) {
flag &= remove(obj);
}
return flag;
}
```
每次循环中,`removeAll`都调用`remove`,这是线性的。所以认为`removeAll`是二次的很诱人。但事实并非如此。
在这种方法中,循环对于每个`collection`中的元素运行一次。如果`collection`包含`m`个元素,并且我们从包含`n`个元素的列表中删除,则此方法是`O(nm)`的。如果`collection`的大小可以认为是常数,`removeAll`相对于`n`是线性的。但是,如果集合的大小与`n`成正比,`removeAll`则是平方的。例如,如果`collection`总是包含`100`个或更少的元素, `removeAll`则是线性的。但是,如果`collection`通常包含的列表中的 1% 元素,`removeAll`则是平方的。
当我们谈论问题规模时,我们必须小心我们正在讨论哪个大小。这个例子演示了算法分析的陷阱:对循环计数的诱人捷径。如果有一个循环,算法往往是 线性的。如果有两个循环(一个嵌套在另一个内),则该算法通常是平方的。不过要小心!你必须考虑每个循环运行多少次。如果所有循环的迭代次数与`n`成正比,你可以仅仅对循环进行计数之后离开。但是,如在这个例子中,迭代次数并不总是与`n`成正比,所以你必须考虑更多。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册