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

时间:2017-03-11 03:45:30

标签: c++ algorithm linked-list

问题陈述如下:

  

给定一个单链表,写一个函数来成对交换元素。例如,如果链表是1-> 2-> 3-> 4-> 5-> 6-> 7那么该函数应该将其改为2-> 1-> 4- > 3-> 6-> 5-> 7,并且如果链表是1-> 2-> 3-> 4-> 5-> 6那么该函数应该将其改为2→1→4-> 3→6-→5

这是我的解决方案:

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;   
    }
}

解决方案的问题是,当它到达函数的末尾时,磁头不再指向列表的开头,因为当前和prev都被移动了。我在网上看到过其他解决方案与我在这里做同样的事情,但也许因为它们是用C而不是C ++实现的,所以它们的代码有一些方面允许头部保持指向开头的清单。

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

3 个答案:

答案 0 :(得分:2)

一旦你进行轻微的范式转换,手头的任务就会简单得多。这可能看起来更复杂,但在稍微思考之后,它的简单性应该是显而易见的。

简单地说:当你遍历列表时,不是携带指针到每对列表元素的第一个,而是携带一个指针指向每对列表元素中的第一个。从表面上看,这听起来很复杂;但是一旦尘埃落定,这就大大简化了手头的任务。

您必须单独存储头指针,并将其传递给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) - > next因此是指向该对中第二个的指针。由于我们如何重复,ptr可以通过合同证明永远不会NULL。因此,如果*ptr为NULL,则到达列表的末尾。但是如果*ptr不是NULL,则至少剩下一个元素,而(* ptr) - > next是" next 2nd element"。如果(*ptr)->next为NULL,则原始列表中包含奇数个元素,因此在最后一次迭代中,您最终使用*ptr指向奇数鸭。在这种情况下你也完成了,不需要再进一步了。

最后:

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

这只会使列表中的两个元素前进ptr。请记住,ptr是一个指向指向列表中接下来两个元素中第一个元素的指针的地方",现在将ptr设置为指向的位置指向***的第一个*** ****列表中的两个元素恰好存在。拿一张纸,绘制一些图表,然后自己弄清楚。不要过去"去",不要收200美元,直到它沉入。

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

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

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

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

现在,那不容易吗?

答案 1 :(得分:1)

将功能的签名更改为

Node* swapPairs(Node* head)

并在第一次交换后保存新头,然后在while循环关闭}后结束,返回新头,以替换调用者持有的旧列表头,这将使用这样的东西:

list = swapPairs(list);

答案 2 :(得分:1)

您可以在函数开头保留指向新头的指针,并使用该函数更新函数末尾的head。请注意,我将参数从Node*更改为Node **,因为我们要更新指针值,以便在更新head时,我们写入传递给此函数的相同内存位置。因此,当我们从函数返回时,head函数的调用者可以获得正确的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
}