将两个链表放在一起而不复制 - Java,使用标准API

时间:2013-08-27 14:39:44

标签: java performance

我的代码中有两个LinkedList,我需要创建一个包含两个的。我将不再需要这个列表,只需要新的列表,它包含我需要的所有数据。

我可以使用.addAll(),但性能是一个巨大的问题,我不能等到每次复制,添加引用,所有内容..

如果我们创建自己的链表,我正在寻找像往常一样的东西,只需将最后一个节点从一个连接到第二个节点。有没有办法使用java api中的LinkedList类做到这一点?


合并集合是一个不同的情况,虽然操作意味着几乎相同,但我的问题仅仅是关于性能和链接列表,通常可以做我需要的。 “合并”也是一个含糊不清的术语,我想要的只是将它们放在一起,无论它们是什么顺序,都考虑到性能。我不知道是否有可能合并......

另一件事,我的问题只是关于API,我不是在寻找构建我自己的代码(老板的要求),这就是为什么与这个不同的原因:在Java中用恒定时间合并两个列表 - 那里没有用的答案任一..

7 个答案:

答案 0 :(得分:3)

如果您只想迭代新列表,并且可以将List替换为Iterable,则可以使用此处所述的Guava Iterable.concat

Combine multiple Collections into a single logical Collection?

答案 1 :(得分:3)

如果您正在使用LinkedList,那么您很可能对索引访问不感兴趣(因为索引访问速度很慢......但请记住,列表只存储引用,因此对于插入很少的非常大的列表/删除你将使用ArrayList提高内存效率,因为它不需要在堆上分配每个节点)

所以你真正想要的东西是给你大部分List合同......或者甚至不是那个。

很可能你想要的只是给你Iterable<String>的东西......如果是这样的话那么你的生活很简单:

public class UberIterable<T> implements Iterable<T> {
  private final List<List<T>> lists;
  public UberIterable(List<T>... lists) {
    this.lists = Arrays.asList(lists); 
  }
  public Iterator<T> iterator() {
    return new Iterator<T>() {
      Iterator<List<T>> metaNext = lists.iterator();
      Iterator<T> next;
      public boolean hasNext() {
        while (true) {
          if (next != null && next.hasNext()) return true;
          if (metaNext.hasNext()) next = metaNext.next(); else return false; 
        }
      }
      public T next() {
        if (!hasNext()) throw new NoSuchElementException();
        return next.next();
      }
      public void remove() {
        throw new UnsupportedOperation();
      }
    }
  }
}

这是一个基本实现,它将为您提供许多列表的合并视图。如果你想获得List的更多合同,你可以重复相同的技巧,只有更好地实现ListIterator,这将获得你可能会追求的很多东西,或者最后通过扩展{{} 1}}并使用新的AbstractList实现覆盖适当的方法

答案 2 :(得分:2)

我担心这样做的唯一方法是使用反射... When you take a look at the source code of LinkedList,你可以看到子类Entry<E>是私有的,如果你想要这是一个问题将第一个和最后一个条目连接到其他条目,以便合并列表。

更新:即使反射也不安全(除非你添加支票),因为JDK 7中的Oracle changed the name of the subclass Entry to Node and changed the order of arguments of the constructor!,这是愚蠢的恕我直言。

肮脏的解决方案:对源代码进行完整的复制粘贴,并将private个关键字更改为public。但是,我不确定Oracle是否允许这样做。检查他们的执照。

答案 3 :(得分:2)

我担心答案是否定的。 Entry使用的内部LinkedList类是私有的,LinkedList公开的所有公共方法都使用常规集合。

您的用例对我来说似乎很合理,但此实现不支持它。

答案 4 :(得分:1)

这样做的一种方法是使用getLast()从其中一个列表中抓取最后一个元素,然后在另一个列表上使用addFirst()以将其添加到前面。

正如在这里所说的那样,addAll()不会复制任何内容,并且可以轻松使用。

如果你的问题是关于LinkedList中节点对象的实际实例化,你可能需要实现自己的版本,在其API中公开更多的实现机制。

答案 5 :(得分:1)

为什么不创建一个实现List的包装器/代理类并包含对2个子列表的引用,然后实现List方法(或者至少是下游需要的方法) - 一点工作但是如果要复制其中一个列表真的是这个问题听起来很值得。

答案 6 :(得分:0)

import java.util.LinkedList;

公共类MergeLinkedList {

public static void main(String[] args) {

    LinkedList<String> mainlist = new LinkedList<String>() ;

    mainlist.add("A");
    mainlist.add("B");

    LinkedList<String> secondlist = new LinkedList<String>() ;

    secondlist.add("C");
    secondlist.add("D");

    mainlist.addAll(secondlist);
    System.out.println(mainlist);
}

}

O / P [A,B,C,D]

你必须使用addall();