链接列表中元素的成对交换(通过更改指针)

Pairwise swapping of elements in a linked list (by changing pointers)

本文关键字:指针 交换 列表 元素 链接      更新时间:2023-10-16

问题语句如下:

给定一个单链接列表,写一个函数以成对交换元素。例如,如果链接列表为1-> 2-> 3-> 3-> 4-> 5-> 6-> 7,则该功能应将其更改为2-> 1-> 1-> 4-> 3-> 3-> 6-> 5 -> 7,如果链接列表为1-> 2-> 3-> 3-> 4-> 5-> 6,则该功能应将其更改为2-> 1-> 1-> 4-> 3-> 3-> 6-> 5 <</p>

这是我的解决方案:

void swapPairs(Node* head) {
    if (!head->next || !head)return head;
    Node* current = head->next;
    Node*prev = head;
    while (true) {
        Node* next = current->next;
        current->next = prev;
        if (!next || !next->next) {
            prev->next = next;
            break;
        }
        prev->next = next->next;
        prev = next;
        current = prev->next;   
    }
}

解决方案的问题是,当它到达函数的末尾时,由于当前和上一个已移动了函数,因此头部不再指向列表的开始。我已经在网上看到了其他解决方案,这些解决方案与我在这里做的事情相同,但是也许由于它们是在C而不是C 实现的,因此它们的代码有些方面可以使头保持指向开始列表。

我意识到这可能是一个非常简单的问题,但是我目前没有看到该解决方案。在整个算法中维护列表开始的最佳方法是什么?

一旦您经历了轻微的范式,手头的任务将变得更加简单。一开始这似乎更复杂,但是在考虑一下之后,它的简单性应该很明显。

简单地说:与其携带一个指针 - 到每对列表元素的第一个 - 当您浏览列表时,请携带指向指针指向每对列表元素的第一个指针。从表面上看,这听起来很复杂。但是,一旦尘埃落定,这将大大简化手头的任务。

您必须单独存储头部指针,然后将其传递给swapPairs()

Node *head;
// The list gets populated here, then ...
swapPairs(head);

这就是您现在正在做的事情。但是不要这样做,而是将指针传递给头节点:

swapPairs(&head);
// ...
void swapPairs(Node **ptr)
{
    while ( (*ptr) && (*ptr)->next)
    {
          // swap the next two elements in the list
          // ...
          // Now, advance by two elements, after swapping them.
          ptr= &(*ptr)->next->next;
    }
}

while循环的主体将交换列表中的下两个元素,让我们暂时跳过该部分,然后专注于通过此链接列表迭代的逻辑,这是一对元素时间。这里发生了什么?

好吧,您正在尝试浏览列表,一次是两个元素。

请记住,ptr不再是指向该对的第一个元素的指针。这是指向两人的第一个元素的指针恰好活着的指针。因此,最初的ptr指向您的原始head指针。

一旦理解,下一个心理飞跃就是要了解您要循环遍及迭代,只要列表中剩下两个元素:

    while ( (*ptr) && (*ptr)->next)

*ptr是列表的下一个元素,该对的第一个元素,(*ptr) ->接下来是对第二个中第二个的指针。由于我们的迭代方式,可以通过合同从不成为NULL来证明ptr。因此,如果*ptr为null,则到达列表的末尾。但是,如果*ptr不是零,则至少剩下一个元素,(*ptr) ->接下来是"下一个第二个元素"。如果(*ptr)->next为null,则原始列表中有奇数元素,因此在最后一次迭代中,您最终以*ptr指向奇数鸭。在这种情况下,您也不需要进一步走。

最后:

ptr= &(*ptr)->next->next;

这只是通过列表的两个元素来推进ptr。请记住,ptr是指向列表"碰巧活着"的下两个元素的指针的指针,现在将ptr设置为指向*** Next ***的第一个指针的位置*列表中的两个元素恰好存在。拿一张纸,画一些图表,然后自己弄清楚。不要通过"去",不要收取200美元,直到陷入困境。

一旦您将大脑包裹起来,唯一剩下的就是交换对。就是这样。循环的主体可以简单地为:

Node *first=*ptr;
Node *second=first->next;
Node *next=second->next;
*ptr=second;
second->next=first;
first->next=next;

就是这样。你完成了。你猜怎么着?您的原始head现在自动指向交换列表的右头节点。

现在,这不是简单吗?

将函数的签名更改为

Node* swapPairs(Node* head)

并在第一次交换后保存新的头,然后在while Loop关闭}之后的结尾,返回该新的头,以替换呼叫者持有的旧列表头,它将使用此内容,例如:

list = swapPairs(list);

您可以在功能开始时将指针保留到新的头部,并在功能结束时更新head。请注意,我将参数从Node*更改为Node **,因为我们想更新指针值,以便当我们更新head时,我们写入传递给此功能的同一内存位置。结果,当我们返回该功能时,将在此功能的呼叫者中可用。

void swapPairs(Node **head) {
  if (!(*head)->next || !(*head))
    return;
  Node *new_head = (*head)->next;    // the new_head
  Node *current = (*head)->next;
  Node *prev = (*head);
  while (true) {
    Node *next = current->next;
    current->next = prev;
    if (!next || !next->next) {
        prev->next = next;
        break;
    }
    prev->next = next->next;
    prev = next;
    current = prev->next;   
  }
  *head = new_head;   // now update the head
}