【问题标题】:Effective Java Item 17: How can overriding removeRange() improve performance?有效的 Java 项目 17:重写 removeRange() 如何提高性能?
【发布时间】:2013-02-27 10:44:53
【问题描述】:

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

这个方法被这个列表上的clear操作调用,它的 子列表。重写此方法以利用 清单的实施可以显着提高 此列表及其子列表上的clear 操作。

我的问题是,重写此方法如何提高性能(不仅仅是不重写它)?谁能举个例子?

【问题讨论】:

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


    【解决方案1】:

    让我们举一个具体的例子 - 假设您的实现由一个动态数组支持(例如,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 以使用这种更高效的算法可以显着提高性能。

    希望这会有所帮助!

    【讨论】:

    • 所以简而言之,如果你的实现优于默认实现,你就有机会提高性能。谢谢!
    • 不一定“优于”,而是“不同”。
    【解决方案2】:

    在方法的 javadocs 中指定:

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

    由于这个抽象类不知道其子类的内部结构,因此它依赖于这种通用算法,该算法的运行时间与被删除的项目数量成正比。

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-01
        • 1970-01-01
        • 2012-06-29
        • 2011-08-01
        • 2014-05-15
        • 2012-02-02
        • 1970-01-01
        相关资源
        最近更新 更多