【问题标题】:Reversing a linked list in Java, recursively递归地反转Java中的链表
【发布时间】:2010-09-26 04:11:10
【问题描述】:

我一直在为一个类从事 Java 项目。它是一个链表的实现(这里称为AddressList,包含称为ListNode 的简单节点)。问题是一切都必须使用递归算法来完成。我能够在没有一种方法的情况下做所有事情:public AddressList reverse()

列表节点:

public class ListNode{
  public String data;
  public ListNode next;
}

现在我的 reverse 函数只是调用一个辅助函数,该函数接受一个参数来允许递归。

public AddressList reverse(){
  return new AddressList(this.reverse(this.head));
}

我的辅助函数的签名是private ListNode reverse(ListNode current)

目前,我让它使用堆栈迭代工作,但这不是规范所要求的。我在 C 中找到了一种算法,它可以递归地逆向并手动将其转换为 Java 代码,并且它可以工作,但我对此并不了解。

编辑:没关系,我在此期间想通了。

private AddressList reverse(ListNode current, AddressList reversedList){
  if(current == null) 
      return reversedList;
  reversedList.addToFront(current.getData());
  return this.reverse(current.getNext(), reversedList);
}

当我在这里时,有人发现这条路线有什么问题吗?

【问题讨论】:

  • 不,您的解决方案没有问题。相反,它甚至比受欢迎的“Little Lisper”解决方案“更好”,因为它让原始列表保持不变。这在多核环境中尤其有价值,在这种环境中,不可变值是非常受欢迎的。

标签: java data-structures recursion linked-list


【解决方案1】:

在一个回复中有代码说明了这一点,但您可能会发现从下往上开始,通过询问和回答小问题更容易(这是 The Little Lisper 中的方法):

  1. null 的反面是什么(空列表)?空。
  2. 单元素列表的反面是什么?元素。
  3. n 元素列表的反面是什么?列表其余部分的倒数,后跟第一个元素。

public ListNode Reverse(ListNode list)
{
    if (list == null) return null; // first question

    if (list.next == null) return list; // second question

    // third question - in Lisp this is easy, but we don't have cons
    // so we grab the second element (which will be the last after we reverse it)

    ListNode secondElem = list.next;

    // bug fix - need to unlink list from the rest or you will get a cycle
    list.next = null;

    // then we reverse everything from the second element on
    ListNode reverseRest = Reverse(secondElem);

    // then we join the two lists
    secondElem.next = list;

    return reverseRest;
}

【讨论】:

  • 哇,我喜欢整个“三个问题”的东西。
  • 谢谢。小问题这件事应该是学习 Lisp 的基础。这也是一种对新手隐藏归纳的方法,本质上就是这种模式。如果您真的想解决这类问题,我建议您阅读 Little Lisper。
  • 例外情况的例外。为什么要对可通过 if 测试的已知条件使用 catch?
  • 我相信您不需要创建变量:secondElem,因为 list.next 仍然是 secondElem。在“ListNode reverseRest = Reverse(secondElem);”之后,可以先做“list.next.next = list”,再做“list.next = null”。就是这样。
  • 你能解释一下为什么 list.next = null 吗?我试图理解这个循环,但没有得到。
【解决方案2】:

我在一次采访中被问到这个问题,我很生气,因为我有点紧张,所以我摸不着头脑。

这应该反转一个单链表,调用 reverse(head,NULL); 所以如果这是你的清单:

1->2->3->4->5->null
它会变成:
5->4->3->2->1->空

    //Takes as parameters a node in a linked list, and p, the previous node in that list
    //returns the head of the new list
    Node reverse(Node n,Node p){   
        if(n==null) return null;
        if(n.next==null){ //if this is the end of the list, then this is the new head
            n.next=p;
            return n;
        }
        Node r=reverse(n.next,n);  //call reverse for the next node, 
                                      //using yourself as the previous node
        n.next=p;                     //Set your next node to be the previous node 
        return r;                     //Return the head of the new list
    }
    

编辑:我对此做了 6 次编辑,这表明它对我来说仍然有点棘手,哈哈

【讨论】:

  • 老实说,如果指定了 Java,我会对面试中的“必须递归”要求感到有点恼火。否则我会选择 p = null; while (n.next != null) {n2 = n.next; n.下一个 = p; p = n; n = n2;} n.next = p;返回n;。 O(N) 堆栈用于鸟类。
  • 哦,是的,还有一个空检查,这是 Java。
【解决方案3】:

我完成了一半(直到 null,以及 plinth 建议的一个节点),但在进行递归调用后丢失了轨道。但是,在阅读 plinth 的帖子后,我想到了以下内容:

Node reverse(Node head) {
  // if head is null or only one node, it's reverse of itself.
  if ( (head==null) || (head.next == null) ) return head;

  // reverse the sub-list leaving the head node.
  Node reverse = reverse(head.next);

  // head.next still points to the last element of reversed sub-list.
  // so move the head to end.
  head.next.next = head;

  // point last node to nil, (get rid of cycles)
  head.next = null;
  return reverse;
}

【讨论】:

  • 非常好。就像做缺点:)
【解决方案4】:

这是另一个递归解决方案。它在递归函数中的代码比其他一些函数少,所以它可能会快一点。这是 C#,但我相信 Java 会非常相似。

class Node<T>
{
    Node<T> next;
    public T data;
}

class LinkedList<T>
{
    Node<T> head = null;

    public void Reverse()
    {
        if (head != null)
            head = RecursiveReverse(null, head);
    }

    private Node<T> RecursiveReverse(Node<T> prev, Node<T> curr)
    {
        Node<T> next = curr.next;
        curr.next = prev;
        return (next == null) ? curr : RecursiveReverse(curr, next);
    }
}

【讨论】:

    【解决方案5】:

    算法需要在以下模型上工作,

    • 跟踪头部
    • 递归直到链表结束
    • 反向链接

    结构:

    Head    
    |    
    1-->2-->3-->4-->N-->null
    
    null-->1-->2-->3-->4-->N<--null
    
    null-->1-->2-->3-->4<--N<--null
    
    null-->1-->2-->3<--4<--N<--null
    
    null-->1-->2<--3<--4<--N<--null
    
    null-->1<--2<--3<--4<--N<--null
    
    null<--1<--2<--3<--4<--N
                           |
                           Head
    

    代码:

    public ListNode reverse(ListNode toBeNextNode, ListNode currentNode)
    {               
            ListNode currentHead = currentNode; // keep track of the head
    
            if ((currentNode==null ||currentNode.next==null )&& toBeNextNode ==null)return currentHead; // ignore for size 0 & 1
    
            if (currentNode.next!=null)currentHead = reverse(currentNode, currentNode.next); // travarse till end recursively
    
            currentNode.next = toBeNextNode; // reverse link
    
            return currentHead;
    }
    

    输出:

    head-->12345
    
    head-->54321
    

    【讨论】:

      【解决方案6】:

      我认为这是更清洁的解决方案,类似于 LISP

      // Example:
      // reverse0(1->2->3, null) => 
      //      reverse0(2->3, 1) => 
      //          reverse0(3, 2->1) => reverse0(null, 3->2->1)
      // once the first argument is null, return the second arg
      // which is nothing but the reveresed list.
      
      Link reverse0(Link f, Link n) {
          if (f != null) {
              Link t = new Link(f.data1, f.data2); 
              t.nextLink = n;                      
              f = f.nextLink;             // assuming first had n elements before, 
                                          // now it has (n-1) elements
              reverse0(f, t);
          }
          return n;
      }
      

      【讨论】:

        【解决方案7】:

        我知道这是一篇旧帖子,但大多数答案都不是尾递归的,即它们在从递归调用返回后执行一些操作,因此不是最有效的。

        这是一个尾递归版本:

        public Node reverse(Node previous, Node current) {
            if(previous == null)
                return null;
            if(previous.equals(head))
                previous.setNext(null);
            if(current == null) {    // end of list
                head = previous;
                return head;
            } else {
                            Node temp = current.getNext();
                current.setNext(previous);
                reverse(current, temp);
            }
            return null;    //should never reach here.
        } 
        

        致电:

        Node newHead = reverse(head, head.getNext());
        

        【讨论】:

        • 您在方法中引用了一个名为“head”的变量,但它没有在任何地方声明。
        • 这可能是List类包含Node head属性的方法
        【解决方案8】:
        无效反向(节点1,节点2){ 如果(node1.next!=null) 反向(node1.next,node1); 节点1.next=节点2; } 将此方法称为 reverse(start,null);

        【讨论】:

          【解决方案9】:
          public Node reverseListRecursive(Node curr)
          {
              if(curr == null){//Base case
                  return head;
              }
              else{
                  (reverseListRecursive(curr.next)).next = (curr);
              }
              return curr;
          }
          

          【讨论】:

            【解决方案10】:
            public void reverse() {
                head = reverseNodes(null, head);
            }
            
            private Node reverseNodes(Node prevNode, Node currentNode) {
                if (currentNode == null)
                    return prevNode;
                Node nextNode = currentNode.next;
                currentNode.next = prevNode;
                return reverseNodes(currentNode, nextNode);
            }
            

            【讨论】:

            • 我认为这是最好的解决方案...简单,尾递归可优化并且只有一次空检查。
            【解决方案11】:
            public static ListNode recRev(ListNode curr){
            
                if(curr.next == null){
                    return curr;
                }
                ListNode head = recRev(curr.next);
                curr.next.next = curr;
                curr.next = null;
            
                // propogate the head value
                return head;
            
            }
            

            【讨论】:

            • 这是最好的解决方案,但不是最好的答案,因为没有给出解释:)。起初我得出了一个类似的解决方案,但失去了头部参考。这个解决方案解决了这个问题。
            【解决方案12】:

            通过递归算法反转。

            public ListNode reverse(ListNode head) {
                if (head == null || head.next == null) return head;    
                ListNode rHead = reverse(head.next);
                rHead.next = head;
                head = null;
                return rHead;
            }
            

            通过迭代

            public ListNode reverse(ListNode head) {
                if (head == null || head.next == null) return head;    
                ListNode prev = null;
                ListNode cur = head
                ListNode next = head.next;
                while (next != null) {
                    cur.next = prev;
                    prev = cur;
                    cur = next;
                    next = next.next;
                }
                return cur;
            }
            

            【讨论】:

            • 不幸的是你的递归反向是错误的!!
            • @SreeAurovindh - 为什么?
            【解决方案13】:

            此解决方案表明不需要任何参数。

            /**
             * Reverse the list
             * @return reference to the new list head
             */
            public LinkNode reverse() {
                if (next == null) {
                    return this; // Return the old tail of the list as the new head
                }
                LinkNode oldTail = next.reverse(); // Recurse to find the old tail
                next.next = this; // The old next node now points back to this node
                next = null; // Make sure old head has no next
                return oldTail; // Return the old tail all the way back to the top
            }
            

            这是支持代码,以证明这是可行的:

            public class LinkNode {
                private char name;
                private LinkNode next;
            
                /**
                 * Return a linked list of nodes, whose names are characters from the given string
                 * @param str node names
                 */
                public LinkNode(String str) {
                    if ((str == null) || (str.length() == 0)) {
                        throw new IllegalArgumentException("LinkNode constructor arg: " + str);
                    }
                    name = str.charAt(0);
                    if (str.length() > 1) {
                        next = new LinkNode(str.substring(1));
                    }
                }
            
                public String toString() {
                    return name + ((next == null) ? "" : next.toString());
                }
            
                public static void main(String[] args) {
                    LinkNode head = new LinkNode("abc");
                    System.out.println(head);
                    System.out.println(head.reverse());
                }
            }
            

            【讨论】:

              【解决方案14】:

              这是一个简单的迭代方法:

              public static Node reverse(Node root) {
                  if (root == null || root.next == null) {
                      return root;
                  }
              
                  Node curr, prev, next;
                  curr = root; prev = next = null;
                  while (curr != null) {
                      next = curr.next;
                      curr.next = prev;
              
                      prev = curr;
                      curr = next;
                  }
                  return prev;
              }
              

              这是一种递归方法:

              public static Node reverseR(Node node) {
                  if (node == null || node.next == null) {
                      return node;
                  }
              
                  Node next = node.next;
                  node.next = null;
              
                  Node remaining = reverseR(next);
                  next.next = node;
                  return remaining;
              }
              

              【讨论】:

                【解决方案15】:

                由于Java总是传值,所以在Java中递归反转链表,确保在递归结束时返回“新头”(反转后的头节点)。

                static ListNode reverseR(ListNode head) {
                    if (head == null || head.next == null) {
                        return head;
                    }
                
                    ListNode first = head;
                    ListNode rest = head.next;
                
                    // reverse the rest of the list recursively
                    head = reverseR(rest);
                
                    // fix the first node after recursion
                    first.next.next = first;
                    first.next = null;
                
                    return head;
                }
                

                【讨论】:

                  【解决方案16】:

                  PointZeroTwo 得到了优雅的答案,在 Java 中也是如此......

                  public void reverseList(){
                      if(head!=null){
                          head = reverseListNodes(null , head);
                      }
                  }
                  
                  private Node reverseListNodes(Node parent , Node child ){
                      Node next = child.next;
                      child.next = parent;
                      return (next==null)?child:reverseListNodes(child, next);
                  }
                  

                  【讨论】:

                  • 这是完美的,因为您并不总是希望该 list 方法将 list 作为参数,而是用它自己的孩子反转自身,谢谢
                  【解决方案17】:
                  public class Singlelinkedlist {
                    public static void main(String[] args) {
                      Elem list  = new Elem();
                      Reverse(list); //list is populate some  where or some how
                    }
                  
                    //this  is the part you should be concerned with the function/Method has only 3 lines
                  
                    public static void Reverse(Elem e){
                      if (e!=null)
                        if(e.next !=null )
                          Reverse(e.next);
                      //System.out.println(e.data);
                    }
                  }
                  
                  class Elem {
                    public Elem next;    // Link to next element in the list.
                    public String data;  // Reference to the data.
                  }
                  

                  【讨论】:

                    【解决方案18】:
                    public Node reverseRec(Node prev, Node curr) {
                        if (curr == null) return null;  
                    
                        if (curr.next == null) {
                            curr.next = prev;
                            return curr;
                    
                        } else {
                            Node temp = curr.next; 
                            curr.next = prev;
                            return reverseRec(curr, temp);
                        }               
                    }
                    

                    调用使用:head = reverseRec(null, head);

                    【讨论】:

                      【解决方案19】:

                      其他人所做的,在其他帖子中是一个内容游戏,我所做的是一个链表游戏,它反转了链表的成员而不是成员的价值。

                      Public LinkedList reverse(LinkedList List)
                      {
                             if(List == null)
                                     return null;
                             if(List.next() == null)
                                    return List;
                             LinkedList temp = this.reverse( List.next() );
                             return temp.setNext( List );
                      }
                      

                      【讨论】:

                      • sry 我忘了你还需要一个辅助方法来设置尾部的下一个,值为空
                      【解决方案20】:
                      package com.mypackage;
                      class list{
                      
                          node first;    
                          node last;
                      
                          list(){
                          first=null;
                          last=null;
                      }
                      
                      /*returns true if first is null*/
                      public boolean isEmpty(){
                          return first==null;
                      }
                      /*Method for insertion*/
                      
                      public void insert(int value){
                      
                          if(isEmpty()){
                              first=last=new node(value);
                              last.next=null;
                          }
                          else{
                              node temp=new node(value);
                              last.next=temp;
                              last=temp;
                              last.next=null;
                          }
                      
                      }
                      /*simple traversal from beginning*/
                      public void traverse(){
                          node t=first;
                          while(!isEmpty() && t!=null){
                              t.printval();
                              t= t.next;
                          }
                      }
                      /*static method for creating a reversed linked list*/
                      public static void reverse(node n,list l1){
                      
                          if(n.next!=null)
                              reverse(n.next,l1);/*will traverse to the very end*/
                          l1.insert(n.value);/*every stack frame will do insertion now*/
                      
                      }
                      /*private inner class node*/
                      private class node{
                          int value;
                          node next;
                          node(int value){
                              this.value=value;
                          }
                          void printval(){
                              System.out.print(value+" ");
                          }
                      }
                      
                       }
                      

                      【讨论】:

                        【解决方案21】:

                        解决办法是:

                        package basic;
                        
                        import custom.ds.nodes.Node;
                        
                        public class RevLinkedList {
                        
                        private static Node<Integer> first = null;
                        
                        public static void main(String[] args) {
                            Node<Integer> f = new Node<Integer>();
                            Node<Integer> s = new Node<Integer>();
                            Node<Integer> t = new Node<Integer>();
                            Node<Integer> fo = new Node<Integer>();
                            f.setNext(s);
                            s.setNext(t);
                            t.setNext(fo);
                            fo.setNext(null);
                        
                            f.setItem(1);
                            s.setItem(2);
                            t.setItem(3);
                            fo.setItem(4);
                            Node<Integer> curr = f;
                            display(curr);
                            revLL(null, f);
                            display(first);
                        }
                        
                        public static void display(Node<Integer> curr) {
                            while (curr.getNext() != null) {
                                System.out.println(curr.getItem());
                                System.out.println(curr.getNext());
                                curr = curr.getNext();
                            }
                        }
                        
                        public static void revLL(Node<Integer> pn, Node<Integer> cn) {
                            while (cn.getNext() != null) {
                                revLL(cn, cn.getNext());
                                break;
                            }
                            if (cn.getNext() == null) {
                                first = cn;
                            }
                            cn.setNext(pn);
                        }
                        

                        }

                        【讨论】:

                          【解决方案22】:
                          static void reverseList(){
                          
                          if(head!=null||head.next!=null){
                          ListNode tail=head;//head points to tail
                          
                          
                          ListNode Second=head.next;
                          ListNode Third=Second.next;
                          tail.next=null;//tail previous head is poiniting null
                          Second.next=tail;
                          ListNode current=Third;
                          ListNode prev=Second;
                          if(Third.next!=null){
                          
                          
                          
                              while(current!=null){
                              ListNode    next=current.next;
                                  current.next=prev;
                                  prev=current;
                                  current=next;
                              }
                              }
                          head=prev;//new head
                          }
                          }
                          class ListNode{
                              public int data;
                              public ListNode next;
                              public int getData() {
                                  return data;
                              }
                          
                              public ListNode(int data) {
                                  super();
                                  this.data = data;
                                  this.next=null;
                              }
                          
                              public ListNode(int data, ListNode next) {
                                  super();
                                  this.data = data;
                                  this.next = next;
                              }
                          
                              public void setData(int data) {
                                  this.data = data;
                              }
                              public ListNode getNext() {
                                  return next;
                              }
                              public void setNext(ListNode next) {
                                  this.next = next;
                              }
                          
                          
                          
                          
                          
                          }
                          

                          【讨论】:

                            【解决方案23】:
                            private Node ReverseList(Node current, Node previous)
                                {
                                    if (current == null) return null;
                                    Node originalNext = current.next;
                                    current.next = previous;
                                    if (originalNext == null) return current;
                                    return ReverseList(originalNext, current);
                                }
                            

                            【讨论】:

                            • 从 ReverseList(head,null) 开始
                            【解决方案24】:
                            //this function reverses the linked list
                            public Node reverseList(Node p) {
                                if(head == null){
                                    return null;
                                }
                                //make the last node as head
                                if(p.next == null){
                                    head.next = null;
                                    head = p;
                                    return p;
                                }
                                //traverse to the last node, then reverse the pointers by assigning the 2nd last node to last node and so on..
                                return reverseList(p.next).next = p;
                            }
                            

                            【讨论】:

                              【解决方案25】:
                              //Recursive solution
                              class SLL
                              {
                                 int data;
                                 SLL next;
                              }
                              
                              SLL reverse(SLL head)
                              {
                                //base case - 0 or 1 elements
                                if(head == null || head.next == null) return head;
                              
                                SLL temp = reverse(head.next);
                                head.next.next = head;
                                head.next = null;
                                return temp;
                              }
                              

                              【讨论】:

                                【解决方案26】:

                                an article 讨论递归数据结构的不可变实现的启发,我使用 Swift 组合了一个替代解决方案。

                                通过突出以下主题的领先答案文档解决方案:

                                1. nil 的反面是什么(空列表)?
                                  • 在这里没关系,因为我们在 Swift 中有 nil 保护。
                                2. 单元素列表的反面是什么?
                                  • 元素本身
                                3. n 元素列表的反面是什么?
                                  • 第二个元素的倒数后跟第一个元素。

                                我已经在下面的解决方案中指出了这些。

                                /**
                                 Node is a class that stores an arbitrary value of generic type T 
                                 and a pointer to another Node of the same time.  This is a recursive 
                                 data structure representative of a member of a unidirectional linked
                                 list.
                                 */
                                public class Node<T> {
                                    public let value: T
                                    public let next: Node<T>?
                                
                                    public init(value: T, next: Node<T>?) {
                                        self.value = value
                                        self.next = next
                                    }
                                
                                    public func reversedList() -> Node<T> {
                                        if let next = self.next {
                                            // 3. The reverse of the second element on followed by the first element.
                                            return next.reversedList() + value
                                        } else {
                                            // 2. Reverse of a one element list is itself
                                            return self
                                        }
                                    }
                                }
                                
                                /**
                                 @return Returns a newly created Node consisting of the lhs list appended with rhs value.
                                 */
                                public func +<T>(lhs: Node<T>, rhs: T) -> Node<T> {
                                    let tail: Node<T>?
                                    if let next = lhs.next {
                                        // The new tail is created recursively, as long as there is a next node.
                                        tail = next + rhs
                                    } else {
                                        // If there is not a next node, create a new tail node to append
                                        tail = Node<T>(value: rhs, next: nil)
                                    }
                                    // Return a newly created Node consisting of the lhs list appended with rhs value.
                                    return Node<T>(value: lhs.value, next: tail)
                                }
                                

                                【讨论】:

                                  【解决方案27】:

                                  使用递归反转链表。这个想法是通过反转链接来调整链接。

                                    public ListNode reverseR(ListNode p) {
                                  
                                         //Base condition, Once you reach the last node,return p                                           
                                          if (p == null || p.next == null) { 
                                              return p;
                                          }
                                         //Go on making the recursive call till reach the last node,now head points to the last node
                                  
                                          ListNode head  = reverseR(p.next);  //Head points to the last node
                                  
                                         //Here, p points to the last but one node(previous node),  q points to the last   node. Then next next step is to adjust the links
                                          ListNode q = p.next; 
                                  
                                         //Last node link points to the P (last but one node)
                                          q.next = p; 
                                         //Set the last but node (previous node) next to null
                                          p.next = null; 
                                          return head; //Head points to the last node
                                      }
                                  

                                  【讨论】:

                                  • 能否请您详细说明您的答案,添加更多关于您提供的解决方案的描述?
                                  • 我添加了 cmets。非常感谢
                                  【解决方案28】:
                                  public void reverseLinkedList(Node node){
                                      if(node==null){
                                          return;
                                      }
                                  
                                      reverseLinkedList(node.next);
                                      Node temp = node.next;
                                      node.next=node.prev;
                                      node.prev=temp;
                                      return;
                                  }
                                  

                                  【讨论】:

                                    【解决方案29】:

                                    javascript中的解决方案(递归):

                                    function reverse_linked_list_1(node){
                                        function reverse_linked_list_1(node, result){
                                            return node ? reverse_linked_list_1(node.next, {data: node.data, next: result}) : result;
                                        }
                                        return reverse_linked_list_1(node, null);
                                    }
                                    

                                    【讨论】:

                                      【解决方案30】:
                                      public void reverse(){
                                          if(isEmpty()){
                                          return;
                                           }
                                           Node<T> revHead = new Node<T>();
                                           this.reverse(head.next, revHead);
                                           this.head = revHead;
                                      }
                                      
                                      private Node<T> reverse(Node<T> node, Node<T> revHead){
                                          if(node.next == null){
                                             revHead.next = node;
                                             return node;
                                           }
                                           Node<T> reverse = this.reverse(node.next, revHead);
                                           reverse.next = node;
                                           node.next = null;
                                           return node;
                                      }
                                      

                                      【讨论】:

                                        猜你喜欢
                                        • 1970-01-01
                                        • 2017-06-22
                                        • 2012-11-05
                                        • 2012-12-14
                                        • 1970-01-01
                                        • 2020-10-02
                                        • 1970-01-01
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多