Java中的链表有快速的concat方法吗?
Posted
技术标签:
【中文标题】Java中的链表有快速的concat方法吗?【英文标题】:Is there a fast concat method for linked list in Java? 【发布时间】:2011-01-30 10:39:26 【问题描述】:如何通过 jdk1.6、google 或 apache commons 集合或其他方式将 O(1) 中的两个链表与 Java 连接起来?例如。在 jdk 中只有 addAll 方法是 O(n)。
我想念的另一个功能是连接两个列表,其中每个列表都可以按相反的顺序排列。为了说明这一点,假设两个列表 a->b->c 和 e->f->g 可以合并到
-
a->b->c->e->f->g
a->b->c->g->f->e
c->b->a->e->f->g
c->b->a->g->f->e
您知道这样的列表实现还是我必须实现自己的链表?了解如何调整现有解决方案也很有帮助(例如 jdk LinkedList 只有很多私有方法)。这些功能在我看来非常明显,希望我没有遗漏一些愚蠢的东西。
正如 MicSim 指出的问题 Merge two lists in constant time in Java 是相关的,但不是真正的重复! 现在的问题是:
-
是否可以使用其他集合库?
如何连接逆?
【问题讨论】:
可能重复。看到这个:***.com/questions/2237308/… 你能用语言中立的方式描述一个算法,它在 O(1) 中连接链表的内容吗? @rocker:欢迎来到 SO。为了将来参考,仅仅因为 SO 的结构方式,最好将甚至相关的主题(在你的情况下,concat 和 inverse)作为单独的问题询问。人们希望能够一次专注于一个主题。 @David:独立于语言,但类似于 java 的算法:firstList.getLastElement().setNextElement(secondList.getFirstElement())
@Roman 这是 O(N),其中 N 是 secondList
的大小。
【参考方案1】:
目前我看到的唯一解决方案是实现List,制作一个像这样的构造函数:
public EnhancedList (List l1, List l2)
并覆盖所有方法。在这样的解决方案中,是否要连接 LinkedLists 或任何其他列表实际上并不重要。
【讨论】:
我实际上虽然会有一个开箱即用的解决方案。如果我必须推出我自己的,我会通过 MyLinkedList.addAll(Collection) -> 检测 LinkedLists 并创建逆: MyLinkedList.inverse() 我只是提出了相同的解决方案(所以 +1 ;))。我认为 Roman 提议的是实现一个 List 接口,以便您可以将此实现用作单个列表,而它的方法适用于创建它的单个列表。例如,新的get
方法将从第一个列表或第二个列表返回一个元素:public T get(int i) return i < list1.size() ? list1.get(i) ? list2.get(i - list1.size());
【参考方案2】:
我认为使用任何类型的基本列表构造编写这都不会太难,因为在链接列表中插入列表的中间或末尾是 O(1)。
【讨论】:
问题是LinkedList
在 Java 中是一个独立的对象,并且执行该操作 同时还保持 LinkedList
对象的完整和独立是 不是 O(1) 操作,因为您必须复制一个列表。
好点,我未能深入挖掘 Java 特定对象。【参考方案3】:
如果你愿意接受 Iterable 结果,你可以使用 google-collections Iterables.concat 和 Iterables.reverse
http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Iterables.html
public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b)
public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b,
Iterable<? extends T> c)
public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b,
Iterable<? extends T> c,
Iterable<? extends T> d)
public static <T> Iterable<T> concat(Iterable<? extends T>... inputs)
public static <T> Iterable<T> concat(Iterable<? extends Iterable<? extends T>> inputs)
【讨论】:
我会说看看代码 - 我怀疑它的性能不如 addAll 。 这些方法创建了一个委托给原始列表的新对象。检查性能/内存影响总是好的,因为这取决于使用情况。 使用 Iterables 方法,您不会复制列表元素,从而减少内存使用量,并且与 addAll 相比可能会提高速度。 使用 ArrayList 我注意到在经常访问迭代器时简单地使用 addAll 并生成一个新列表要快得多。这在我们的代码中经常发生,使用 addAll 时我们的性能提高了 50%。 ;-)【参考方案4】:在以下情况下,调整 LinkedList 以在 jdk 中获得 O(1) concat 将起作用:
-
方法 entry() 和变量 header 和 size 以及内部类 Entry 将受到保护
addAll 会检测 LinkedList 然后做某事。喜欢:
JdkLinkedList secondList = (JdkLinkedList) secondColl;
int numNew = secondList.size();
if (numNew == 0) return false;
modCount++;
Entry<E> successor = (index == size ? header : entry(index));
Entry<E> predecessor = successor.previous;
// TODO LATER if reverse
// connect the last element of this list with the first element of the second list
// linked list is implemented as a 'cycle' => header.next == first element of second list
Entry<E> first = secondList.header.next;
predecessor.next = first;
first.previous = predecessor;
// append the last element of the second list with the rest of this list
Entry<E> last = secondList.header;
successor.previous = last;
last.next = successor;
【讨论】:
【参考方案5】:对于 concat,我建议您执行以下操作:
确保所有参数/变量都声明为 List<...> 而不是 LinkedList<...> 改变新的链表<...>();到新的 ArrayList<...>(); 配置应用程序 将新的 ArrayList<...> 更改为新的 LinkedList<...>(); 配置应用程序根据您的使用情况,ArrayList 可能比 LinkedList 快得多。还可以查看配置文件数据,您可以看到使用 addAll 对性能有多大影响 - 如果它不是那么大,请不要费心“修复”它。
对于某些事情,您使用其他语言的经验并不适用。您可能会发现 addAll 符合您在 Java 中的要求。
如果您要编写自己的可连接列表,请确保它符合 List 接口,然后更改您的代码并重新配置它并确保它更快。如果不是,则将其丢弃并坚持使用标准 List 类型。
【讨论】:
我确信在我的用例中,链表的 concat 会比 arraylist 的 system.copy 更快 更多...例如,如果您对列表进行大量迭代,则对链表进行迭代的成本将超过对数组列表的迭代成本。因此,在 addAll 中花费的时间可能会抵消发送迭代的时间。还有其他类似的东西可以使 ArrayList 的整体性能比 LinkedList 更快。但实际上,永远不要假设性能 - 总是衡量。 当然我会测试差异!但问题是关于一种快速的 concat 方法,而不是关于整体性能。 但是一个快速的 concat 可能在性能方面毫无意义,这可能解释了为什么一个 doers 不存在。【参考方案6】:FastList from javolution 不是开箱即用的解决方案,但 tail() 和 head() 非常接近我的最爱。
我认为trove 是解决方案,尽管在 O(1) 中不存在用于 invert 或 addAll 的便捷方法。
【讨论】:
以上是关于Java中的链表有快速的concat方法吗?的主要内容,如果未能解决你的问题,请参考以下文章