【问题标题】:Swap reversing a linked list in c在c中交换反转链表
【发布时间】:2019-03-03 15:23:34
【问题描述】:

给定一个列表,我想通过将第一个与最后一个交换,第二个与倒数第二个交换,以此类推。

我编写了这个函数来交换每一对,其中pos1pos2 是要交换的两个位置。

maxPos 是两个位置中最大的一个, node1node2 是遍历列表后找到的两个节点。

int swap(struct node *list, int pos1, int pos2) {

    if (node1 != NULL && node2 != NULL) {
        if (prev1 != NULL)
            prev1->next = node2;
        if (prev2 != NULL)
            prev2->next = node1;
        temp        = node1->next;
        node1->next = node2->next;
        node2->next = temp;
        if (prev1 == NULL)
            head = node2;
        else if (prev2 == NULL)
            head = node1;
    }
    return 1;
}

而不是为每一对递归地调用它,即。 (1,n-1), (2,n-2), (3,n-3) 每次都要遍历列表,想知道有没有办法迭代解决。

【问题讨论】:

  • 请为递归工作的代码创建一个minimal reproducible example,为询问替代解决方案提供基础。照原样,您的程序中没有足够的关于几个细节的信息。例如。类型定义。
  • @Yunnosch 我已经尽可能地清理它以使其可读。谢谢。
  • @Fredrik,我不确定在这种情况下如何使用 for 循环。喜欢第一个和最后一个元素?
  • calling this recursively for each pair, ie. (1,n-1), (2,n-2), (3,n-3) 通常不被称为递归。递归可能会记住外部节点,将自身应用于没有这些节点的列表,并在最后一个节点之前添加第一个节点作为其结果。但是:鉴于一个很好的迭代过程来反转单链表,为什么创建一个劣质递归的?
  • @Fredrik 说头部被写为 void **head 并且内存已被分配 for 循环会是什么样子?

标签: c pointers recursion linked-list iterator


【解决方案1】:

您真的要交换节点内容吗?

您可以使用一个非常简单的函数迭代地反转列表:

struct node {
    // whatever payload fields...
    struct node *next;
};

struct node *reverse_list(struct node *list) {
    struct node *last = NULL;
    while (list != NULL) {
        struct node *next = list->next;
        list->next = last;
        last = list;
        list = next;
    }
    return last;
}

【讨论】:

    【解决方案2】:

    当使用带有锚元素的列表时(例如,第一个元素是节点但不用于存储数据),您可以使用

    struct node **list_nth(struct node *node, size_t idx)
    {
        for (;idx > 0 && node; --idx)
            node = node->next;
    
        return node ? &(node->next) : NULL;
    }
    
    void list_swap(struct node *head, size_t idx_a, size_t idx_b)
    {
        struct node **a = list_nth(head, min(idx_a, idx_b));
        struct node **b = list_nth(head, max(idx_a, idx_b));
        struct node *tmp;
    
        if (idx_a == idx_b)
            return;
    
        if (!a || !b)
            abort();
    
        if ((*a)->next == *b) {
            tmp = *a;
    
            *a  = *b;
            tmp->next = (*b)->next;
            (*a)->next = tmp;
        } else {
            tmp        = (*a)->next;
            (*a)->next = (*b)->next;
            (*b)->next = tmp;
    
            tmp = *a;
            *a  = *b;
            *b  = tmp;
        }
    }
    

    用于交换操作。但是对于单链表,由于昂贵的节点查找,您的反向操作具有 O(n^2) 的复杂性。

    如其他地方所述,用于反转列表:

    • 使用双链接的
    • 用 O(n) 反向迭代它
    • 移除元素 (O(1))
    • 将元素附加到新的头部 (O(1))
    • 将新列表合并到旧列表中 (O(1))

    【讨论】:

      【解决方案3】:

      您必须声明一个新方法来反转整个列表,该方法只会被调用一次。另外你最好使用双向链表来解决这个问题。

      节点结构:

      struct node {
          int data;
          struct node *next;
          struct node *prev;
      };
      

      方法:

      void reverse() {
      
          struct node *temp = head; // assuming you have the head node as a global variable.
          struct node *lastPtr = head;
      
          for (int i = 0; i < len; i++) { // assuming you have length as a global variable.
              lastPtr = lastPtr->next;
          }
      
          for (int i = 0; i < len / 2; i++) {
              temp->data += lastPtr->data;
              lastPtr->data = temp->data - lastPtr->data;
              temp->data -= lastPtr->data;
              temp = temp->next;
              lastPtr = lastPtr->prev;
          }
      }
      

      【讨论】:

      • @MuhammedGui temp->data += lastPtr->data;这是做什么的?是在 temp 和 lastPtr 中添加值吗?
      • @JDoe 是的。该行和以下 2 行用于交换两个节点之间的数据。
      • 那么这个例子中的结构节点是什么样子的呢?结构节点 { int 数据; struct node *next;} 我是对的。
      • 我假设您使用的是双向链表,因为我使用了 'lastPtr->prev;'。所以结构节点必须是这样的:{ int data;结构节点*下一个;结构节点 *prev; } 其中 'prev' 指向前一个节点。
      • 你不回答问题,你不交换单元格而是交换它们的值
      猜你喜欢
      • 1970-01-01
      • 2012-01-30
      • 2016-03-19
      • 1970-01-01
      • 1970-01-01
      • 2012-10-26
      • 2016-04-22
      • 2012-12-14
      • 1970-01-01
      相关资源
      最近更新 更多