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