撤消链接列表

时间:2011-11-01 04:33:47

标签: java data-structures linked-list time-complexity reverse

所以我需要在O(N)时间/空间中反转链接列表。

我实现了这个实现,只使用了Java标准库中的LinkedList类(它不允许我自己访问节点)。

4 个答案:

答案 0 :(得分:4)

您要求的“更好的方法”可以利用Java LinkedList类具有方法的事实

  • addFirst
  • addLast
  • removeFirst
  • removeLast

其中每一项都是O(1)。

您可以通过以下几种方式获得O(n)时间和空间行为。一种方法是:

LinkedList<E> b = new LinkedList<E>();
while (!a.isEmpty()) {
    b.addFirst(a.removeFirst());
}
a.addAll(b);

这反转“就地”(即变量a始终引用完全相同的对象)。它等同于使用堆栈作为临时存储(b是“堆栈”)。

尽管丑陋的复制,但它是O(n)时间和O(n)空间。

答案 1 :(得分:3)

不,不是。 input.get(idx);本身就是O(idx)及时,这使得您的实施在时间上呈二次方式。

您可能希望使用迭代器(或更好的listIterator)。

编辑:此外,你可以通过一点重新安排轻松消除holdPopped。

holdPopped.add在时间和空间上都是平凡的O(1),因为你通过传递大小来预先分配空间(在空间中是O(n))。

IIRC,holdLL.add也在时间和空间上摊销O(1)。有时它会更多,有时更少,但是总空间是n,所以它应该平均到O(n)。您可以使用holdLL.ensureCapacity

简化分析

答案 2 :(得分:1)

Java API有一个在O(n)中完成的方法:Collections.reverse(List<?> list)。假设这是家庭作业,你应该自己实现,但在现实生活中你会使用库函数。

或者,您可以创建一个反转装饰器,使反转O(1)。这个概念的一个例子如下。

public class ReversedLinkedList<T> extends LinkedList<T> {

  private final LinkedList<T> list;

  public ReversedLinkedList(LinkedList<T> list) {
    this.list = list;
  }

  public Iterator<T> descendingIterator() {
    return list.iterator();
  }

  public Iterator<T> iterator() {
    return list.descendingIterator();
  }

  public T get(int index) {
    int actualIndex = list.size() - index - 1;
    list.get(actualIndex);
  }

  // Etc.
}

请注意,使装饰器扩展具体类通常(总是?)不良形式。理想情况下,您应该实现公共接口并接受构造函数参数作为公共接口的实例。上面的例子纯粹是为了说明的目的,因为LinkedList碰巧实现了很多接口(例如Dequeue,List等)。

此外,在这里插入典型的“过早优化是邪恶的”评论 - 如果你的列表实际上是一个瓶颈,你只会在现实生活中创建这个反向出列的类。

答案 3 :(得分:0)

您应该始终检查 apache commons ,他们通常会对链接列表集合进行更好,更灵活的实施;

https://commons.apache.org

其次,如果你想要反转列表,你可以更容易地使用双向链表