Java LinkedList:从

时间:2017-10-28 22:07:00

标签: java list linked-list

我的java.util.LinkedList包含逻辑上像

的数据
1 > 2 > 3 > 4 > 5 > null

我想删除2到4之间的元素,并像这样LinkedList

1 > 5 > null

实际上,我们应该能够在O(n)复杂度下实现这一点,因为你必须在2处将链断开并在一次操作中将其连接到5。

在Java LinkedList中,我无法找到任何允许在单个O(n)操作中使用from和to从链表中删除链的函数。

它只为我提供了单独删除元素的选项(使每个操作O(n))。

我是否可以在一次操作中完成此操作(不编写自己的List)?

此处提供的一个解决方案使用单行代码解决问题,但不能在单个操作中解决。 list.subList(1, 4).clear();

问题在于算法和性能。当我检查性能时,这实际上比逐个删除元素慢。我猜这个解决方案实际上并没有删除o(n)中的整个子列表,而是为每个元素逐个删除(每次删除O(n))。还要添加额外的计算来获取子列表。

  

以ms为单位的1000000次计算的平均值:

     

没有子列表= 1414
  使用提供的子列表解决方案:= 1846 **

2 个答案:

答案 0 :(得分:6)

一步到位的方法是

list.subList(1, 4).clear();

,如java.util.LinkedList#subList(int, int)的Javadoc所述。

检查了源代码后,我发现这最终会逐个删除元素。 subList继承自AbstractList。此实现返回List,当您在其上调用removeRange时,它只会在支持列表上调用clearremoveRange也是从AbstractList继承的,实现是

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();
    }
}

正如您所看到的,这会一次删除一个元素。在listIterator中重写了LinkedList ,它开始于通过跟踪链接从列表的开头或结尾来查找第一个节点(取决于是否{ {1}}位于列表的前半部分或后半部分中。这意味着fromIndex具有时间复杂度

list.subList(i, j).clear()

除了你最好从最后开始并以相反顺序删除元素的情况之外,我不相信有一个明显更快的解决方案。测试代码的性能并不容易,很容易被错误的结论所吸引。

无法使用O(j - i + min(i, list.size() - i)). 类的公共API一次性删除中间的所有元素。这让我感到惊讶,因为使用LinkedList而不是LinkedList唯一原因是你应该能够有效地从中间插入和删除元素,所以我认为这个案例值得优化(特别是因为它很容易编写)。

如果你绝对需要通过

等电话获得的ArrayList表现
O(1)

你要么必须编写自己的实现,要么用这样的反射做一些脆弱和不明智的事情:

list.subList(1, list.size() - 1)).clear();

答案 1 :(得分:1)

要删除单个操作(方法调用)中的中间元素,您可以继承java.util.LinkedList,然后调用List.removeRange(int, int)

list.removeRange(1, 4);

(感谢发布此答案的人然后将其删除。:))但是,即使这种方法也会调用ListIterator.remove() n次。

我不相信有一种方法可以从java.util.LinkedList中删除n个连续的条目,而无需在引擎盖下执行n个操作。

一般情况下,从任何链接列表中删除n个连续项似乎需要O(n)操作,因为必须一次从一个项目从起始索引遍历到结束索引 - 固有地 - 以便找到下一个列表条目修改后的清单。