我正在编写一些非常热门的代码,我需要将一个LinkedList
(l1
)的元素添加到另一个LinkedList
({{1} })。
无法使用l2
方法,因为它使用addAll(Collection)
来迭代整个Iterator
。
在我看来,应该可以将Collection
的{{1}}设置为指向Node
的第一个l1
。但是我找不到合适的方法吗?我是否需要自己的Node
实现来实现这一目标?
答案 0 :(得分:5)
根据评论,目标是在连接列表上创建类似“视图”的内容 - 这意味着数据应该不被复制。相反,给定的列表应该“显示”为单个列表。
如何实现这一点的一种方法是扩展AbstractList
。 get(int)
和size()
的实施相当简单。关键点是为连接列表创建Iterator
。以下是关于如何实现这一目标的非常简单草图(但请参阅下面的注释)
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class MergedListTest
{
public static void main(String[] args)
{
testBasic();
testEmptyA();
testEmptyB();
}
private static void testBasic()
{
List<Integer> list0 = Arrays.asList(0,1,2);
List<Integer> list1 = Arrays.asList(3,4,5);
List<Integer> expected = Arrays.asList(0,1,2,3,4,5);
List<Integer> actual = new MergedList<Integer>(list0, list1);
System.out.println(actual.equals(expected));
}
private static void testEmptyA()
{
List<Integer> list0 = Collections.emptyList();
List<Integer> list1 = Arrays.asList(3,4,5);
List<Integer> expected = Arrays.asList(3,4,5);
List<Integer> actual = new MergedList<Integer>(list0, list1);
System.out.println(actual.equals(expected));
}
private static void testEmptyB()
{
List<Integer> list0 = Arrays.asList(0,1,2);
List<Integer> list1 = Collections.emptyList();
List<Integer> expected = Arrays.asList(0,1,2);
List<Integer> actual = new MergedList<Integer>(list0, list1);
System.out.println(actual.equals(expected));
}
}
class MergedList<T> extends AbstractList<T>
{
private final List<T> list0;
private final List<T> list1;
MergedList(List<T> list0, List<T> list1)
{
this.list0 = list0;
this.list1 = list1;
}
@Override
public T get(int index)
{
if (index < list0.size())
{
return list0.get(index);
}
return list1.get(index - list0.size());
}
@Override
public Iterator<T> iterator()
{
return new Iterator<T>()
{
private Iterator<T> current = list0.iterator();
private boolean first = true;
@Override
public boolean hasNext()
{
return current != null && current.hasNext();
}
@Override
public T next()
{
T result = current.next();
if (!current.hasNext())
{
if (first)
{
current = list1.iterator();
}
else
{
current = null;
}
}
return result;
}
};
}
@Override
public int size()
{
return list0.size() + list1.size();
}
}
从概念上讲,从AbstractSequentialList
继承会更有意义:AbstractList
提供存根实现,例如最终委托给iterator()
的{{1}},而get(int)
提供“对立”存根实现,例如最终委托给AbstractSequentialList
的{{1}}。但是,这需要get(int)
实现,这比上面的简单草图更加繁琐。
另请注意,我假设生成的视图应该不可修改 - 但这应该与给定的描述一致。
最后,请注意,(当然)已经实现了此类和类似任务,并且这些实现可能远比上面概述的更复杂。例如,Google Guava提供了不同的Iterators#concat
方法,允许您连接多个迭代器。因此,如果您已经在使用Guava,那么上面iterator()
方法的实现可以归结为
ListIterator<T>
答案 1 :(得分:2)
标准库似乎不支持所需的功能。但是,您可以使用反射在合并链接列表时实现恒定时间。 我没有正确测试以下代码,只是为了说明如何实现:
public class ListConcatenation {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
LinkedList<String> list1 = new LinkedList<>();
list1.add("a");
list1.add("b");
list1.add("c");
LinkedList<String> list2 = new LinkedList<>();
list2.add("d");
list2.add("e");
list2.add("f");
System.out.println(merge(list1, list2));
}
public static List<String> merge(List<String> list1, List<String> list2) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
Field first = getDeclaredField(LinkedList.class, "first");
Field last = getDeclaredField(LinkedList.class, "last");
Field size = getDeclaredField(LinkedList.class, "size");
Class<?> nodeClass = Class.forName("java.util.LinkedList$Node");
Field next = nodeClass.getDeclaredField("next");
next.setAccessible(true);
Object list1Last = last.get(list1);
Object list2First = first.get(list2);
Object list2Last = last.get(list2);
// link the last element of list1 with the first element of list2
next.set(list1Last, list2First);
// set last element of list1 equal to the last element of list2
last.set(list1, list2Last);
// update list1 size
size.set(list1, list1.size() + list2.size());
return list1;
}
private static Field getDeclaredField(Class<?> clazz, String name) throws NoSuchFieldException {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field;
}
}
答案 2 :(得分:2)
没有。您不能在常量时间O(1)中添加两个java.util.LinkedList
来输出另一个{。}。
从概念上讲,您确实可以在恒定时间O(1)中将两个链接列表数据结构一起添加,但它们需要以正确的方式实现。正如您所提到的,实现应该通过将最后一个节点连接到第一个节点来组合两个列表,而不是遍历任何一个列表。