扭转单链表

时间:2016-05-31 10:22:01

标签: java linked-list reverse singly-linked-list

在求职面试中,我被要求撤销一个链接列表。以下是我的解决方案:

public class E<T>{
    private E<T> next;
    private T val;

    private E(T val) {
        this.val = val;
    }

    public static <T> E<T> createNode(T val){
        return new E<T>(val);
    }

    public E<T> add(E<T> next){
        E<T> current = this;
        while(current.next != null){
            current = current.next;
        }
        current.next = next;
        return this;
    }

    public E<T> reverse(){
        if(this.next == null)
            return this;
        E<T> previous = new E<>(this.val); //<----- HERE
        E<T> current = this.next;
        while(current != null){ 
            E<T> tmp = current.next;
            this.val = current.val;
            this.next = previous;
            current.next = previous;
            previous = current;
            current = tmp;
        }
        return this;
    }
}

但它确实看起来很难看。我无法理解如何处理的问题是我们最初只有this引用,我们无法分配给任何东西(我们最后只有一个循环)。这就是我创建一个新节点的原因。但它看起来像一个可怕的解决方法。有没有“真正的方法”呢?

4 个答案:

答案 0 :(得分:1)

如果你出于某种原因你不能使用像Collections.reverse这样的集合实用程序函数,就像Mena告诉你可以大致实现的那样:

public Iterable<T> Reverse<T>(Iterable<T> queue)
{
    Stack<T> stack = new Stack<T>();  
    while(!queue.isEmpty())
       stack.push(queue.pop());

    return stack;
}

(*这是伪代码不是真正的实现)

编辑:inplace version

public void Reverse<T>(Iterable<T> queue)
{   
    //todo: add null check
    Stack<T> stack = new Stack<T>();  
    while(!queue.isEmpty())
       stack.push(queue.pop());

    while(!stack.isEmpty())
       queue.append(stack.pop());
}

答案 1 :(得分:1)

嗯,这样做的一种方法是使用递归:

public E<T> reverse() {
    if (this.next == null) return this;
    E<T> node = this.next.reverse();
    this.next.next = this;
    this.next = null;
    return node;
}

我测试了它,这很顺利,但如果列表太长,你可能会遇到麻烦:调用堆栈可能会爆炸。

迭代方式:

public E<T> reverse() {
    E<T> previous = null;
    E<T> current = this;
    E<T> next = this.next;
    while (next != null) {
        current.next = previous;
        previous = current;
        current = next;
        next = current.next;
    }
    current.next = previous; // We haven't reversed the last node yet.
    return current;
}

同样,这已经过测试,并产生了预期的效果。

此外,可以改进add方法,使其占用恒定时间:

public E<T> add(E<T> node) {
    node.next = this;
    return node;
}

答案 2 :(得分:1)

您将有权访问HEAD节点。因此,您可以从HEAD节点开始,只需更改链接的方向直到结束。最后,将HEAD-&gt; next设为null,将最后一个节点设为HEAD。

喜欢的东西。 (我还没有对它进行测试..只是在一些伪代码中写出这个想法)

cur = head.next;
prev = head;

while(cur)
{
    next = cur.next;
    cur.next = prev;
    prev = cur;
    cur = next;
} 

head.next = null;
head = cur;

答案 3 :(得分:1)

这是一个解决问题的递归代码:

public E<T> reverse() {
    if(next == null) return this;
    else {
        E<T> r = next.reverse();
        this.next = null;
        r.add(this);
        return r;
    }
}

这里是以迭代方式解决问题的代码:

public E<T> reverse() {
    E<T> n = this;
    E<T> last = null;

    while(n.next != null) {
        E<T> temp = n.next;
        n.next = last;
        last = n;
        n = temp;
    }

    n.next = last;

    return n;
}