【问题标题】:Swapping neighbor linked list nodes交换邻居链表节点
【发布时间】:2020-11-18 19:32:41
【问题描述】:

我必须创建一个函数,将链表中的相邻节点与哨兵交换。像这样:1-2-3-4-5 -> 2-1-4-3-5,但我不知道该怎么做。有人可以帮帮我吗?

#include <stdio.h>
#include <stdlib.h>

typedef struct _listelem {
    int a;
    struct _listelem* next;
} listelem;

void reverse_pairs(listelem* a)
{
    listelem* head = NULL;
    listelem* tail = NULL;
    head = a->next;
    tail = a->next;
    while (head->next != NULL)
    {
        head = head->next->next;
        tail = head;
    }
    return head;
}

【问题讨论】:

  • 什么是“带哨兵的链表”?
  • @VladfromMoscow 见这里:en.wikipedia.org/wiki/Sentinel_node#Linked_list_implementation。但这只是一种可能的解释,它是模棱两可的。
  • @Csaba Bársics 此函数 void reverse_pairs(listelem* a) 具有返回类型 void。所以你可能不会使用语句 return head;
  • @Csaba Bársics 提供显示列表是如何构建的代码。
  • @VladfromMoscow,那里有一个拿着枪的家伙在处理它????????

标签: c linked-list swap singly-linked-list sentinel


【解决方案1】:

您没有展示如何构建带有哨兵节点的列表。

我假设哨兵节点是指针头指向的链表中的第一个节点。

在这种情况下,函数可以如下所示。

void reverse_pairs( listelem *head )
{
    if (head)
    {
        for (; head->next && head->next->next; head = head->next->next)
        {
            listelem *tmp = head->next;
            head->next = head->next->next;

            tmp->next = head->next->next;
            head->next->next = tmp;
        }
    }
}

至于你的函数实现,那么它至少是不正确的,因为返回类型为void 的函数可能没有这样的语句

return head;

也在这个while循环中

while (head->next != NULL)
{
    head = head->next->next;
    tail = head;
}

您正在更改局部变量 headtail。此类更改不会影响原始列表。

如果当最后一个节点的数据成员next 指向head(哨兵)节点时,您有一个循环列表,则该函数可以如下所示。

void reverse_pairs( listelem *head )
{
    if (head)
    {
        for ( listelem *current = head; 
              current->next != head && current->next->next != head; 
              current = current->next->next)
        {
            listelem *tmp = current->next;
            current->next = current->next->next;

            tmp->next = current->next->next;
            current->next->next = tmp;
        }
    }
}

【讨论】:

  • 是的,如果参数中没有返回或额外的间接级别,交换第一个和第二个节点将令人失望:)
  • 谢谢,您的代码有效,除了带有奇数元素的列表 S-->1-->2-->3-->S=>S-->2-->1- ->S!
  • @CsabaBársics 你有一个循环列表吗?从你的问题来看,这还不清楚。
  • 不,我没有循环列表,只有一个带有标记节点的链表,如下所示:S-->1-->2-->3-->S
  • @CsabaBársics 正如我所说,您必须展示列表是如何创建的。
【解决方案2】:

虽然@VladFromMoscow 的答案显示了交换列表中的节点以实现您的目标的正确方法,但如果您无法传递单个指针,并且函数返回类型固定为void,那么还有另一种方法解决方法。

您只需在节点之间交换int 成员值,而不是交换节点。以这种方式处理问题,第一个节点的地址永远不会改变,因此无需将列表的地址作为参数传递。

方法很简单。取当前节点,在当前节点和下一个节点之间交换整数值,然后越过持有交换整数的节点。为此,您从当前节点前进到下一个节点并检查下一个节点是否为NULL(标记列表的末尾)。如果是NULL,你就完成了。如果不是NULL,则再次前进并重复。您可以使用while() 循环编写函数,例如

void reverse_pairs (listelem *head)
{
    while (head && head->next) {
        int tmp = head->a;
        head->a = head->next->a;
        head->next->a = tmp;
        
        head = head->next;
        if (head->next)
            head = head->next;
    }
}

或者,可读性稍差,使用for() 循环和三元,例如

void reverse_pairs (listelem *head)
{
    for (; head && head->next;
            head = head->next->next ? head->next->next : NULL) {
        int tmp = head->a;
        head->a = head->next->a;
        head->next->a = tmp;
    }
}

使用/输出示例

对于最后一个指针为NULL 的普通列表,您的输出打印原始列表,调用reverse_pairs(),然后输出修改后的列表如下所示:

$ ./bin/lls_revpairs
 1 2 3 4 5
 2 1 4 3 5

完整的测试代码

完整的测试代码如下。正常编译将使用上面的for() 循环,或者将定义-DUSEWHILE 添加到您的编译字符串将导致使用函数的while() 循环形式:

#include <stdio.h>
#include <stdlib.h>

typedef struct _listelem {
    int a;
    struct _listelem* next;
} listelem;

/** add node at end of list, update tail to end */
listelem *add (listelem **head, int v)
{
    listelem **ppn = head,                      /* pointer to pointer to head */
               *pn = *head,                     /* pointer to head */
             *node = malloc (sizeof *node);     /* allocate new node */
 
    if (!node) {                                /* validate allocation */
        perror ("malloc-node");
        return NULL;
    }
    node->a = v;                                /* initialize members values */
    node->next = NULL;
 
    while (pn) {
        ppn = &pn->next;
        pn = pn->next;
    }
 
    return *ppn = node;    /* add & return new node */
}

#ifdef USEWHILE
/** reverse node pairs in list - while loop */
void reverse_pairs (listelem *head)
{
    while (head && head->next) {
        int tmp = head->a;
        head->a = head->next->a;
        head->next->a = tmp;
        
        head = head->next;
        if (head->next)
            head = head->next;
    }
}
#else
/** reverse node pairs in list - for loop + ternary */
void reverse_pairs (listelem *head)
{
    for (; head && head->next;
            head = head->next->next ? head->next->next : NULL) {
        int tmp = head->a;
        head->a = head->next->a;
        head->next->a = tmp;
    }
}
#endif

/** print all nodes in list */
void prn_list (listelem *l)
{
    if (!l) {
        puts ("list-empty");
        return;
    }
    size_t i = 0;
    for (listelem *n = l; n && i < 10; n = n->next, i++)
        printf (" %d", n->a);
    putchar ('\n');
}

int main (void) {
    
    listelem *list = NULL;
    
    for (int i = 1; i <= 5; i++)
        add (&list, i);
    
    prn_list (list);
    reverse_pairs (list);
    prn_list (list);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    • 2018-11-05
    相关资源
    最近更新 更多