Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java LinkedList:从删除到_Java_List_Linked List - Fatal编程技术网

Java LinkedList:从删除到

Java LinkedList:从删除到,java,list,linked-list,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从LinkedList中删除链 它只为我提供了一个单独删除元

我有一个
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从LinkedList中删除链

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

我是否可以在一次操作中实现这一点(无需编写自己的列表)

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

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

平均1000000次计算(毫秒): 无子列表=1414
使用提供的子列表解决方案:=1846**


一步到位的方法是

list.subList(1, 4).clear();
如Javadoc for中所述

在检查了源代码之后,我发现最终会一次删除一个元素<代码>子列表
继承自
抽象列表
。此实现返回一个
列表
,当您在支持列表上调用
清除
时,该列表只调用支持列表上的
删除范围
removeRange
也是从
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();
    }
}
除了从末尾开始并以相反的顺序删除元素更好的情况之外,我不相信有一个明显更快的解决方案。测试代码的性能并不容易,很容易得出错误的结论

<>代码不能使用“代码> LIKEDLIST/<代码>类的公共API,一次删除中间的所有元素。这让我很惊讶,因为使用
LinkedList
而不是
ArrayList
的唯一原因是您应该能够从中间高效地插入和删除元素,所以我认为这个案例值得优化(特别是因为它很容易编写)

如果您绝对需要从以下调用中获得的
O(1)
性能:

list.subList(1, list.size() - 1)).clear();
您将不得不编写自己的实现,或者使用以下反射执行一些脆弱和不明智的操作:

public static void main(String[] args) {
    LinkedList<Integer> list = new LinkedList<>();
    for (int a = 0; a < 5; a++)
        list.add(a);
    removeRange_NEVER_DO_THIS(list, 2, 4);
    System.out.println(list);       // [0, 1, 4]
}

public static void removeRange_NEVER_DO_THIS(LinkedList<?> list, int from, int to) {
    try {
        Method node = LinkedList.class.getDeclaredMethod("node", int.class);
        node.setAccessible(true);
        Object low = node.invoke(list, from - 1);
        Object hi = node.invoke(list, to);
        Class<?> clazz = low.getClass();
        Field nextNode = clazz.getDeclaredField("next");
        Field prevNode = clazz.getDeclaredField("prev");
        nextNode.setAccessible(true);
        prevNode.setAccessible(true);
        nextNode.set(low, hi);
        prevNode.set(hi, low);
        Field size = LinkedList.class.getDeclaredField("size");
        size.setAccessible(true);
        size.set(list, list.size() - to + from);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
publicstaticvoidmain(字符串[]args){
LinkedList=新建LinkedList();
对于(int a=0;a<5;a++)
列表.添加(a);
删除此操作(列表,2,4);
System.out.println(列表);//[0,1,4]
}
public static void remove_NEVER_DO_THIS(链接列表,int-from,int-to){
试一试{
方法节点=LinkedList.class.getDeclaredMethod(“节点”,int.class);
node.setAccessible(true);
Object low=node.invoke(列表,从-1开始);
Object hi=node.invoke(list,to);
Class clazz=low.getClass();
字段nextNode=clazz.getDeclaredField(“下一个”);
字段prevNode=clazz.getDeclaredField(“prev”);
nextNode.setAccessible(true);
prevNode.setAccessible(true);
nextNode.set(低、高);
prevNode.set(高、低);
字段大小=LinkedList.class.getDeclaredField(“大小”);
size.setAccessible(true);
size.set(list,list.size()-to+from);
}捕获(例外e){
抛出新的运行时异常(e);
}
}

要在单个操作(方法调用)中删除中间元素,可以将
java.util.LinkedList子类化,然后将调用公开给:

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

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


一般来说,从任何链表中删除n个连续项似乎需要O(n)个操作,因为从开始索引到结束索引必须一次遍历一个项(本质上是这样),以便在修改后的列表中找到下一个列表项。

您是否有一个或其他类型的[LinkedList]?问题针对java.util.LinkedList。感谢您的澄清!谢谢你的解决方案。这一步就解决了这个问题,但问题更多的是算法和性能。当我检查性能时,这实际上比逐个删除元素要慢。我猜这个解决方案实际上并没有删除o(n)中的整个子列表,而是一个接一个地删除(每个o(n))。还添加了额外的计算以获取子列表。**平均1000000次计算(毫秒):无子列表=1414,提供的子列表解决方案:=1846**请注意,如果您最终移除头部或最后一个,新的反思性答案可能会中断。另外,LinkedList在removeRange中效率低下(这就是这个答案下面所使用的),这可能算是一个库错误。是的,我不确定为什么我使用反射包含该代码。这真是个糟糕的主意。谢谢你的更新。我向Java提交了特性请求。做得好。应在LinkedList中明确覆盖removeRange。我想不出一个很好的理由来解释为什么它没有被删除。它被删除是因为它是一个受保护的方法
public static void main(String[] args) {
    LinkedList<Integer> list = new LinkedList<>();
    for (int a = 0; a < 5; a++)
        list.add(a);
    removeRange_NEVER_DO_THIS(list, 2, 4);
    System.out.println(list);       // [0, 1, 4]
}

public static void removeRange_NEVER_DO_THIS(LinkedList<?> list, int from, int to) {
    try {
        Method node = LinkedList.class.getDeclaredMethod("node", int.class);
        node.setAccessible(true);
        Object low = node.invoke(list, from - 1);
        Object hi = node.invoke(list, to);
        Class<?> clazz = low.getClass();
        Field nextNode = clazz.getDeclaredField("next");
        Field prevNode = clazz.getDeclaredField("prev");
        nextNode.setAccessible(true);
        prevNode.setAccessible(true);
        nextNode.set(low, hi);
        prevNode.set(hi, low);
        Field size = LinkedList.class.getDeclaredField("size");
        size.setAccessible(true);
        size.set(list, list.size() - to + from);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
list.removeRange(1, 4);