交换链接列表的相邻节点

时间:2013-01-10 18:02:04

标签: algorithm data-structures

我必须在链表中交换两个相邻节点(而不是它们的数据)。 例如 1)输入a-> b-> c-> d-> e-> f,输出:b-> a-> d-> c-> f-> e 2)输入a-> b-> c-> d-> e,输出:b-> a-> d-> c-> e

我写了下面的代码是否有更有效的方法(可能有两个临时指针)或简单的逻辑?

node* swap(node* head) {
   node *first = head;
   node *second,*third,*result;

   if(head == NULL || head->next == NULL) {
        return head;
   }

    result = second = first->next;
    third = second->next;

    while(second != NULL) {
       second->next=first;
       first->next=(third->next==NULL ? third : third->next);
       first=third;
       second=(third->next==NULL ? third : third->next);
       third=(second==NULL ? second : second->next);
    }
    return result;
}

5 个答案:

答案 0 :(得分:3)

你可以通过递归相当简单地做到这一点:

// Swaps node b and c.
void swapTwo(node* a, node* b, node* c) {
   if (a != NULL)
       a->next = c;
   b->next = c->next;
   c->next = b;
}

void swapEveryTwo(node* prev, node* node) {
    if (node != null && node->next != null) {
        swapTwo(prev, node, node->next);
        swapEveryTwo(node->next, node->next->next);
    }
}

swapEveryTwo的每次调用都会交换节点对,然后为下一对设置递归。此外,由于此函数是尾递归的,因此编译器无疑会将其优化为while循环,从而确保不会分配额外的堆栈帧,因此将是最佳的。如果您需要进一步解释,请随时提出。

已修改为原始帖子中添加swap功能:

node* swap(node *head) {
    if (head != NULL && head->next != NULL) {
        node *newHead = head->next;
        swapEveryTwo(NULL, head);
        return newHead;
    } else {
        return head;
    }
}

答案 1 :(得分:2)

您的算法是最好的。通常我们可以通过简单性获得一点速度。考虑从输入列表的头部弹出元素并使用队列add-to-tail操作来构建结果,而不是绘制关于指针的图片和推理。在伪代码中,我们有

set_empty(rtn);
while (head) {
   fst = pop(head);
   if (head) {
     snd = pop(head);
     add_at_tail(rtn, snd);
   }
   add_at_tail(rtn, fst);
}

仅需要if来防止输入列表具有奇数长度的情况。如果我们确定列表的长度是均匀的,我们可以跳过它。

现在pop非常容易实现。如果我们使用虚拟头节点,则add-to-tail操作最简单。所以在C中,我们有:

node *swap(node *head)
{
  node dummy[1];         // set_empty(rtn);
  node *rtn = dummy;
  while (head) {
    node *fst = head;    // fst = pop(head);
    head = head->next;
    if (head) {
      node *snd = head;  // snd = pop(head);
      head = head->next;
      rtn->next = snd;   // add_to_tail(rtn, snd);
      rtn = rtn->next;
    }
    rtn->next = fst;     // add_to_tail(rtn, fst);
    rtn = rtn->next;
  }
  rtn->next = NULL;      // terminate tail
  return dummy->next;
}

现在我还没有测试过这段代码,但我很确定它会运行很好的模数,也许是一两个错字。测试比你的少(每个元素只有一个)。测试相对昂贵,因为它们可能会干扰流水线操作,所以我的应该运行得更快一点。几乎可以肯定,这种差异是无关紧要的。

但是,我认为我的代码更容易理解。当然,这只是一种偏见,但在维护期间可读性确实很重要。

NB 现在我做了一个快速测试,它第一次尝试就开始了!另一方面,当我尝试你的代码时,我得到了一个segv

 first->next=(third->next==NULL ? third : third->next);

以下是测试框架。你看错了吗?

typedef struct node_s {
  struct node_s *next;
  int val;
} node;

// swap goes here

int main(void)
{
  node dummy[1];
  node *p = dummy;

  for (int i = 0; i < 16; i++) {
    p->next = malloc(sizeof(node));
    p = p->next;
    p->next = NULL;
    p->val = 'a' + i;
  }
  p = swap(dummy->next);
  while (p) {
    printf("%c ", p->val);
    p = p->next;
  }
  printf("\n");
  return 0;
}

答案 2 :(得分:1)

看起来不错。我添加了一个正确性检查(第三个== NULL)并删除了一个冗余表达式。您只需浏览整个列表一次,您必须这样做。所以我认为我们可以肯定这是最快的方法。

node* swap(node* head) {
   node *first = head;
   node *second,*third,*result;

   if(head == NULL || head->next == NULL) {
        return head;
   }

    result = second = first->next;
    third = second->next;

    while(second != NULL) {
       second->next=first;
       second = first->next=((third==NULL || third->next==NULL) ? third : third->next);
       first=third;
       third=(second==NULL ? second : second->next);
    }
    return result;
}

答案 3 :(得分:1)

在JavaScript中

LinkedList.prototype.swapPairs = function() {
    var recurse = function(current) {
        if (!current) return this;
        if (current.next) {
            var save = current.next.value;
            current.next.value = current.value;
            current.value = save;
            current = current.next;
        }
        return recurse(current.next);
    }.bind(this);
    return recurse(this.head);
}

答案 4 :(得分:0)

Alex DiCarlo的递归方法更简单,但需要稍微纠正。

void swapEveryTwo(node* prev, node* node) {
    if (node != null && node->next != null) {
        swapTwo(prev, node, node->next);
        swapEveryTwo(node, node->next);
    }
}

如果我错了,请纠正我。

谢谢!