有效的Java项目17:如何覆盖removeRange()提高性能?

时间:2013-03-12 02:50:51

标签: java list data-structures override effective-java

在Joshua Bloch撰写的Effective Java一书中,讨论了一个班级如何提供“明智选择的受保护方法”作为其内部工作的钩子。
然后,作者引用AbstractList.removeRange()中的文档:

  

此方法由此列表上的clear操作及其调用   子列表。重写此方法以利用内部的   列表实现可以大大提高性能   此列表及其子列表上的clear操作。

我的问题是,如何覆盖此方法可以提高性能(而不仅仅是不会覆盖它)?谁能举个例子?

3 个答案:

答案 0 :(得分:19)

让我们举一个具体的例子 - 假设您的实现由动态数组支持(例如,这就是ArrayList的工作原理)。现在,假设您要删除[start,end]范围内的元素。 removeRange的默认实现方法是使迭代器定位start,然后调用remove()适当的次数。

每次调用remove()时,动态数组实现都必须对位置start + 1处的所有元素进行混洗,然后向前移回一个点以填充已删除元素中剩余的空白。这可能需要花费时间O(n),因为可能所有的数组元素都需要被拖垮。这意味着如果你要从列表中删除总共k个元素,那么天真的方法需要花费时间O(kn),因为你正在做O(n)个工作k次。

现在考虑一个更好的方法:将位置end的元素复制到位置start,然后将元素end + 1复制到位置start + 1等,直到复制所有元素。这要求您只执行O(n)工作,因为每个元素最多移动一次。与朴素算法给出的O(kn)方法相比,这是一个巨大的性能提升。因此,覆盖removeRange以使用此更高效的算法可以显着提高性能。

希望这有帮助!

答案 1 :(得分:11)

如方法的javadocs中所指定的那样:

  

此实现获取一个位于fromIndex之前的列表迭代器,并重复调用ListIterator.next,后跟ListIterator.remove,直到删除整个范围。

由于这个抽象类不知道它的子类的内部,它依赖于这个通用算法,该算法将在时间上与被删除的项目数成比例。

例如,如果您实现了一个将元素存储为链接列表的子类。然后,您可以利用此事实并重写此方法,以使用链接列表特定算法(将指针移动到fromIndex以指向toIndex),该算法在恒定时间内运行。因此,您可以利用内部优势提高性能。

答案 2 :(得分:0)

只需覆盖此方法,您就可以根据您的要求使用此通用算法作为索引问题。因为它是AbstractList中的受保护方法,也是ArrayList及其实现中的一个,它作为remove()的迭代调用,需要每次将删除元素右侧可用的所有元素移位一个索引。 显然它没有效果,所以你可以让它更好地工作。