【问题标题】:Removing range (tail) from a List从列表中删除范围(尾部)
【发布时间】:2012-06-03 14:08:09
【问题描述】:

是否有一种有效的方法可以从List 中删除 X 元素的范围(例如尾部),例如LinkedList 在 Java 中?

显然可以一个一个地删除最后一个元素,这应该会导致 O(X) 级别的性能。至少对于 LinkedList 实例,它应该有可能具有 O(1) 性能(通过设置要删除的第一个元素周围的引用并设置头/尾引用)。不幸的是,我在ListLinkedList 中没有看到任何方法可以一次性删除最后一个元素。

目前我正在考虑使用List.subList()替换列表,但我不确定这是否具有相同的性能。至少在代码中会更清楚,另一方面我会失去LinkedList 提供的附加功能。

我主要将 List 用作堆栈,LinkedList 似乎是最好的选择,至少在语义方面。

【问题讨论】:

  • 您是否阅读过 subList() 的注意事项 - 即它只是一个视图,如果支持列表在结构上被修改,那么所有的赌注都将失败?
  • 您的 O(1) 性能忽略了查找最后 N 个元素的 O(N) 成本。

标签: java list collections stack


【解决方案1】:

subList(list.size() - N, list.size()).clear() 是删除最后一个 N 元素的推荐方法。确实,Javadoc for subList特别推荐了这个成语:

此方法无需显式范围操作(通常存在于数组中的那种)。通过传递 subList 视图而不是整个列表,任何需要列表的操作都可以用作范围操作。例如,以下成语从列表中删除一系列元素:

 list.subList(from, to).clear();

确实,我怀疑这个习惯用法可能比调用removeLast()N高效,因为一旦找到Nth-to -last 节点,只需要更新链表中固定数量的指针,而不是每次更新最后一个N 节点的指针。

【讨论】:

  • 对于ArrayList,根据我的测试,速度与明显的while (list.size() > max) list.remove(list.size() - 1);差不多
  • @ThomasMueller 这是很好的信息!当然,我仍然会使用上面的方法,因为在某些情况/实现中它可能会更快。在我看来,这至少与单独删除每个元素一样清楚。它似乎是为这个用例设计的,所以使用不太可能失败 - 让我们使用它!
【解决方案2】:

注意subList() 返回原始列表的视图,意思是:

  1. 对视图所做的任何修改都将反映在原始列表中
  2. 返回的列表不是LinkedList - 它是List 的内部实现,不可序列化

无论如何,使用 removeFirst()removeLast() 应该足够有效,因为在 Java 中弹出链表的第一个或最后一个元素是一个 O(1) 操作 - 在内部,LinkedList 持有指向两端的指针列表并删除其中任何一个就像将指针移动一个位置一样简单。

为了一次删除 m 元素,你会被 O(m) 的性能所困扰,LinkedList,尽管奇怪的是 ArrayList 可能是更好的选择,因为删除 @987654332 末尾的元素@ 就像将索引指针(表示数组的末尾)向左移动一个位置一样简单,并且没有垃圾节点像LinkedList 那样悬空。最佳选择?尝试这两种方法,分析它们并让数字说明一切。

【讨论】:

    猜你喜欢
    • 2017-08-22
    • 2016-06-05
    • 2022-01-08
    • 2015-02-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 2022-06-11
    相关资源
    最近更新 更多