【问题标题】:How to reverse a singly linked list using only two pointers?如何仅使用两个指针来反转单链表?
【发布时间】:2010-12-20 13:38:28
【问题描述】:

我想知道是否存在一些逻辑来反转仅使用两个指针的单链表。

下面是使用pqr三个指针来反转单链表:

struct node {
    int data;
    struct node *link;
};

void reverse() {
    struct node *p = first,
                *q = NULL,
                *r;

    while (p != NULL) {
        r = q;
        q = p;
        p = p->link;
        q->link = r;
    }
    first = q;
}

还有其他替代方案可以反转链表吗?就时间复杂度而言,反转单链表的最佳逻辑是什么?

【问题讨论】:

  • 不是真的,那是两个队列而不是两个指针。
  • 因为你是来帮忙的,而不是玩代表游戏?
  • GMan:就是这样,我不确定我是否在帮助任何人,即使是他,如果他不能坚持到底。​​span>
  • 您正在帮助我们这些阅读并从问题和答案中获得一些东西的人。我发现它很有见地。

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


【解决方案1】:

您可以仅使用一个 Extra 指针简单地反转链接列表。 而做到这一点的关键是使用递归。

这是Java程序。

public class Node {
   public int data;
   public Node next;
}

public Node reverseLinkedListRecursion(Node p) {
    if (p.next == null) {
        head = p;
        q = p;
        return q;
    } else {
        reverseLinkedListRecursion(p.next);
        p.next = null;
        q.next = p;
        q = p;
        return head;
    }
}

// call this function from your main method.
 reverseLinkedListRecursion(head);

如您所见,这是一个头递归的简单示例。 我们主要有两种不同的递归。

  1. 头递归:- 当递归是函数执行的第一件事时。
  2. 尾递归:- 当递归是函数执行的最后一件事时。

这里程序会一直递归调用自己,直到我们的指针“p”到达最后一个节点,然后在返回堆栈帧之前,我们将头指向最后一个节点和额外的指针“q”来构建链表向后的方向。

这里堆栈帧会一直返回,直到堆栈为空。

【讨论】:

    【解决方案2】:

    这里有一个更简单的 python 版本。它确实只使用了两个指针slow & fast

    def reverseList(head: ListNode) -> ListNode:
    
        slow = None
        fast = head
        while fast:  
            node_next = fast.next
            
            fast.next = slow
            slow = fast
                
            fast = node_next
        return slow
    

    【讨论】:

    • OP 的意图是使用 2 个变量,无论它们是指针还是变量。
    【解决方案3】:

    只需使用XOR linked list,它在恒定时间内“自然可逆”,只需交换第一个和最后一个(头和尾)指针。

    void reverse() noexcept { std::swap(first_, last_); }
    

    我已经上传了a working example as a project on my GitHub

    【讨论】:

      【解决方案4】:

      使用 1 个变量的解决方案(仅 p):

      typedef unsigned long AddressType;
      
      #define A (*( AddressType* )&p )
      #define B (*( AddressType* )&first->link->link )
      #define C (*( AddressType* )&first->link )
      
      /* Reversing linked list */
      p = first;
      
      while( first->link )
      {
          A = A + B + C;
          B = A - B - C;
          A = A - B;
          C = A - C;
          A = A - C;
      }
      
      first = p;
      

      【讨论】:

      • 您使用 first 作为变量(被您实际使用 first->link 的事实所掩盖,但它仍然是一个变量。)
      【解决方案5】:

      你可以使用递归方法:

      这是伪代码:

      Node* reverse(Node* root)
      {
          if(!root) return NULL;
      
          if(!(root->next)) temp = root;
          else
          {
              reverse(root->next);
              root->next->next = root;
              root->next = NULL;
          }
      
          return temp;
      }
      

      函数调用后,返回链表的新根[temp]。 很明显,它只使用了两个指针。

      【讨论】:

      • @MohdAdnan,你关心理解代码吗?该代码仅用于反转链表。仅供参考,您从哪里获得打印链表的逻辑?我在这里没有看到任何打印声明,对吧?
      • 是的,对不起。我应该对下面的问题发表评论,但在这里错误地发表了评论。但是现在我只是浏览了你写的代码,我发现了一个可能的缺陷。您没有收集递归调用返回的值,因此我认为应该将其更改为 temp = reverse(root->next);
      • @MohdAdnan:我们不需要收集reverse的返回值。请注意 temp 将是链表的新根,我们只需要在调用者函数中返回它的值。
      【解决方案6】:
      //with this no extra space and no extra scans but this code is reversing code but read
      // in reverse direction no changes made in the linked list 
      PrintInReverse(Node node)
      {
         // given list is null
         if(node ==null)
             return null;
         // if list contains only one node
         if(node->next ==null)
         {
             print(node.value)
         }
         // call recursively 
         else
         {
             //while(node->next != null)// due to while loop it goes into infinite loop.use //if
             if(node->next!=NULL)
             {
                 PrintInReverse(node->next)
                 print(node.value)
             }
         }
      }
      
      Add comments...
      

      【讨论】:

      • (1) 这不会反转链表。 (2) 你随时都有无限循环node->next != null
      • 问题是反转一个链表而不是逆序打印链表。
      猜你喜欢
      • 2020-09-02
      • 1970-01-01
      • 2021-09-25
      • 2021-01-14
      • 1970-01-01
      • 2017-01-04
      • 2014-02-27
      相关资源
      最近更新 更多