【问题标题】:How can I reverse a linked list?如何反转链表?
【发布时间】:2012-02-23 00:25:15
【问题描述】:

考虑:

 Node reverse(Node head) {
    Node previous = null;
    Node current = head;
    Node forward;

    while (current != null) {
        forward = current.next;
        current.next = previous;
        previous = current;
        current = forward;
    }

    return previous;
}

它究竟是如何反转列表的?

我知道它首先将第二个节点设置为forward。然后它说current.next 等于null 节点previous。然后它说previous 现在是current。最后current 变成forward

我似乎无法理解这一点以及它是如何逆转的。有人可以解释一下这是如何工作的吗?

【问题讨论】:

  • from __future__ import braces ?
  • 我的错..已修复到 java!
  • 1.这段代码好像不是python... 2. list reverse是一个基本的算法,网上可以找到很多相关资料
  • 我会在一张纸上画一个3节点的小链表,然后一步一步地过一遍算法,看看会发生什么。你可以在调试器中做同样的事情,但在纸上做这件事会迫使你真正思考每个状态是如何变化的。
  • Techlead 是你吗???

标签: java algorithm data-structures linked-list singly-linked-list


【解决方案1】:

【讨论】:

  • 只有 Techlead 知道。你怎么知道... xaxa
【解决方案2】:

代码只是遍历列表并反转链接,直到到达前一个尾部,它作为新的头部返回。

之前:

Node 1 (Head) -> Node 2 -> Node 3 -> Node 4 (Tail) -> null

之后:

   null <- Node 1 (Tail) <- Node 2 <- Node 3 <- Node 4 (Head)

【讨论】:

  • 我认为他想了解“代码”。 “reverse”的意思很明显,“code”不是。
【解决方案3】:

您迭代地反转列表,并且始终正确反转区间 [head, previous] 中的列表(因此当前是第一个未正确设置其链接的节点)。在每个步骤中,您都执行以下操作:

  • 您记住当前的下一个节点,以便您可以从它继续
  • 您将当前的链接设置为指向上一个,如果您考虑一下,这是正确的方向
  • 您将先前更改为当前,因为现在当前也已正确设置其链接
  • 您将未正确设置其链接的第一个节点更改为第一步中记住的节点

如果你对所有节点都这样做,你可以证明(例如通过归纳法)列表将被正确地反转。

【讨论】:

    【解决方案4】:
    public Node getLastNode()
    {
        if(next != null)
            return next.getLastNode();
        else
            return this;
    }
    
    public Node reverse(Node source)
    {
        Node reversed = source.getLastNode();
        Node cursor = source;
    
        while(cursor != reversed)
        {
            reversed.addNodeAfter(cursor.getInfo());
            cursor = cursor.getNodeAfter();
        }
    
        source = reversed;
        return source;
    }
    

    【讨论】:

      【解决方案5】:

      最简单的思考方式是这样思考:

      1. 首先将链表的头部添加到一个新的链表中。
      2. 不断迭代原始并不断在新链表头部之前添加节点。

      图表:

      最初:

      Original List -> 1 2 3 4 5
      New List -> null
      

      第一次迭代

      Original List -> 1 2 3 4 5
      New List -> 1->null [head shifted to left, now newHead contains 1 and points to null]
      

      第二次迭代

      Original List -> 1 2 3 4 5
      New List -> 2-> 1->null [head shifted to left, now newHead contains 2 and points to next node which is 1]
      

      第三次迭代

      Original List -> 1 2 3 4 5
      New List ->3 -> 2-> 1->null [head shifted to left, now newHead contains 2 and points to next node which is 1]
      

      现在它一直循环到最后。所以最后新的列表变成了:

        New List->  5 -> 4 -> 3 -> 2 -> 1 -> null
      

      相同的代码应该是这样的(使其易于理解):

      /**
       * Definition for singly-linked list.
       * public class ListNode {
       *     int val;
       *     ListNode next;
       *     ListNode(int x) { val = x; }
       * }
       */
      
      public ListNode reverseList(ListNode head) {
          if(head == null) {
              return null;
          }
      
          if(head.next == null) {
              return head;
          }
      
          ListNode current = head;
          ListNode previous = new ListNode(head.val);
          previous.next = null;
      
          while(current.next != null) {
              current = current.next;
              previous = addBeforeHead(current, previous);
          }
      
          return previous;
      }
      
      private ListNode addBeforeHead(ListNode node, ListNode head) {
          if (node == null) return null;
          ListNode temp = new ListNode(node.val);
      
          temp.next = head;
          head = temp;
      
          return head;
      }
      

      【讨论】:

      • 为什么分配新的ListNodes 时,任务不是返回具有相反顺序的值的列表,而是reverse a linked list? (为什么为单元素列表分配新节点?可以结合特殊情况:if (head == null || head.next == null) return head;
      • @greybeard 是的,可以做到。但是我做的方式更容易理解,也不会占用额外的内存。
      • 也许关闭语法高亮?
      【解决方案6】:

      我称之为“樱桃采摘”。这个想法是最小化掉期的数量。交换发生在近索引和远索引之间。这是一个twp-pass算法。

          (Odd length)  A -> B -> C -> D -> E
          (Even length) A -> B -> C -> D
      
          Pre-Condition: N >= 2
      
          Pass 1: Count N, the number of elements
      
          Pass 2:
                  for(j=0 -> j<= (N/2 -1))
                  {
                    swap(j, (N-1)-j)
                  }
      

      示例 1

         For above Odd length list, N = 5 and there will be two swaps
      
            when j=0, swap(0, 4) // Post swap state: E B C D A
            when j=1, swap(1, 3) // Post swap state: E D C B A
      
      
         The mid point for odd length lists remains intact.
      

      示例 2

         For above Even length list, N = 4 and there will be two swaps
      
            when j=0, swap(0, 3) // Post swap state: D B C A
            when j=1, swap(1, 2) // Post swap state: D C B A
      
      • 交换仅适用于数据,不适用于指针,并且可能会遗漏任何完整性检查,但您明白了。

      【讨论】:

      • 不错。但是,一个前提是我们需要知道链表的长度。
      • 是的,这就是为什么它的 2-pass。但是第二遍所需的交换次数总是
      【解决方案7】:

      基本思想是将头节点从第一个列表中分离出来,并将其附加到第二个列表的头上。不断重复,直到第一个列表为空。

      伪代码:

      function reverseList(List X) RETURNS List
         Y = null
         WHILE X <> null
            t = X.next
            X.next = Y
            Y = X
            X = t
         ENDWHILE
         RETURN Y
      ENDfunction
      

      如果您希望保持原始列表不受干扰,则可以使用辅助函数递归地编写复制版本。

      function reverseList(List X) RETURNS List
         RETURN reverseListAux(X, null)
      ENDfunction
      
      function reverseListAux(List X, List Y) RETURNS List
         IF X = null THEN
             RETURN Y
         ELSE
             RETURN reverseListAux(X.next, makeNode(X.data, Y))
      ENDfunction
      

      请注意,辅助函数是尾递归的。这意味着您可以使用迭代创建复制反转。

      function reverseList(List X) RETURNS List
         Y = null
         WHILE X <> null
           Y = makeNode(x.data, Y)
           X = X.next   
         ENDWHILE
         RETURN Y
      ENDfunction
      

      【讨论】:

        【解决方案8】:

        使用迭代反转单链表:

        current = head // Point the current pointer to the head of the linked list
        
        while(current != NULL)
        {
            forward = current->link; // Point to the next node
            fforward = forward->link; // Point the next node to next node
            fforward->link = forward; // 1->2->3,,,,,,,,,this will point node 3 to node 2
            forward->link = current; // This will point node 2 to node 1
        
            if(current == head)
                current->link = NULL; // If the current pointer is the head pointer it should point to NULL while reversing
        
            current = current->link; // Traversing the list
        }
        head = current; // Make the current pointer the head pointer
        

        【讨论】:

          【解决方案9】:
            list_t *reverse(list_t *a)
            {
              list_t *progress = NULL;
              while(a)
              {
                list_t *b; //b is only a temporary variable (don't bother focusing on it)
                b = a->next;
                a->next = progress; // Because a->next is assigned to another value,
                                    // we must first save a->next to a different
                                    // variable (to be able to use it later)
                progress = a; // progress is initially NULL (so a->next = NULL
                              // (because it is the new last element in the list))
                a = b; // We set a to b (the value we saved earlier, what
                       // a->next was before it became NULL)
                /*
                  Now, at the next iteration, progress will equal a, and a will equal b.
                  So, when I assign a->next = progress, I really say, b->next = a.
                  and so what we get is: b->a->NULL.
                  Maybe that gives you an idea of the picture?
          
                  What is important here is:
                    progress = a
                  and
                    a = b
          
                  Because that determines what a->next will equal:
                    c->b->a->0
          
                  a's next is set to 0
                  b's next is set to a
                  c's next is set to b
                */
              }
              return progress;
            }
          

          【讨论】:

            【解决方案10】:

            单链表反转函数的实现:

            struct Node
            {
                int data;
                struct Node* link;
            }
            
            Node* head = NULL;
            
            void reverseList()
            {
                Node* previous, *current, *next;
                previous = NULL;
                current = head;
            
                while(current != NULL)
                {
                    next = current-> link;
                    current->link = previous;
                    previous = current;
                    current = next;
                }
            
                head = previous;
            }
            

            【讨论】:

              【解决方案11】:

              这是一个反转单链表的简单函数

              // Defining Node structure
              
              
              public class Node {
              int value;
              Node next;
              
              
              public Node(int val) {
                  
                  this.value=val;
              }
              

              }

              public LinkedList reverse(LinkedList list) {
                  
                  if(list==null) {
                      
                      return list;
                  }
                  
                  Node current=list.head;
                  Node previous=null;
                  Node next;
                  
                  while(current!=null) {
                      
                      next=current.next;
                      
                      current.next=previous;
                      
                      previous=current;
                      
                      current=next;
                      
                  }
                  
                  list.head=previous;
                  
                  return list;
                  
                  
                  
                  
              }
              

              为了更好的理解,你可以观看这个视频https://youtu.be/6SYVz-pnVwg

              【讨论】:

                【解决方案12】:

                如果你想使用递归:

                         class Solution {
                
                         ListNode root=null;
                
                         ListNode helper(ListNode head)
                         {
                             if (head.next==null)
                             {  root= head;
                                 return head;}
                
                             helper (head.next).next=head;
                             head.next=null;
                
                             return head;
                         }
                
                
                         public ListNode reverseList(ListNode head) {
                             if (head==null)
                             {
                                 return head;
                             }
                             helper(head);
                             return  root;
                
                         }
                     }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-10-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多