【问题标题】:Reversing a singly-linked list反转单链表
【发布时间】:2016-09-29 07:24:57
【问题描述】:

在一次工作面试中,我被要求反转一个单链表。这是我的解决方案:

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 引用,我们无法分配给任何东西(当时我们只是结束了一个循环)。这就是我创建一个新节点的原因。但它看起来是一个糟糕的解决方法。有没有“真正的方法”来做到这一点?

【问题讨论】:

  • 你知道Collections.reverse(List&lt;?&gt; list),对吧?
  • 我认为他应该在面试中真正了解算法。
  • @Mena 这个问题是纯粹的算法问题,但是是的,我认为类似的东西已经在 J​​DK 中了。
  • @Alupkers 问题是,即使您在实际算法上进行了测试,而不是您的 Java 知识,您也可以查看Collections.reverse 的源代码。 Java 中与集合相关的东西据说是高度优化的,所以你可以盯着一些相当不错的源代码并从那里找出来(来自 javadoc:“这个方法在线性时间内运行”)。
  • @Mena 是的,我只是看了一下。它使用 两个 迭代器(start-end 和 end-start),这并不能完全满足我的要求。

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


【解决方案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;
}

【讨论】:

  • 很遗憾,不会。它包含与我犯的相同的错误...您正在分配this。它引入了一个引用循环。我们不能分配this,只能分配this.next
  • @Alupkers 我的代码有问题,但它与引用循环无关。我更正了node.next = this --> this.next.next = this
  • 这取决于操作的顺序。如果你以正确的方式进行操作,就没有问题。在我的代码中,我在其后续元素被反转后分配它。欢迎您在我的代码中添加一些打印以了解操作是如何执行的。
【解决方案2】:

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

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;
}

【讨论】:

    【解决方案3】:

    您将可以访问 HEAD 节点。因此,您可以从 HEAD 节点开始,然后将链接的方向更改到最后。最后,将您的 HEAD->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;
    

    【讨论】:

      【解决方案4】:

      如果你因为某些原因不能使用 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;
      }
      

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

      编辑:就地版本

      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());
      }
      

      【讨论】:

      • 不是我想要的。我们必须改变原始列表。这就是问题所在......
      猜你喜欢
      • 1970-01-01
      • 2018-10-16
      • 1970-01-01
      • 1970-01-01
      • 2020-02-06
      • 2012-10-08
      • 2012-01-30
      相关资源
      最近更新 更多