所以我需要在O(N)时间/空间中反转链接列表。
我实现了这个实现,只使用了Java标准库中的LinkedList类(它不允许我自己访问节点)。
答案 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))。
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 ,他们通常会对链接列表和集合进行更好,更灵活的实施;
其次,如果你想要反转列表,你可以更容易地使用双向链表。