【问题标题】:swap in doubly linked list交换双向链表
【发布时间】:2015-12-11 06:15:28
【问题描述】:

我正在尝试交换双向链表中的两个节点。下面是具有交换功能的程序部分。

 int swap (int x, int y)
{
    struct node *temp = NULL ;
    struct node *ptr1, *ptr2;
    temp = (struct node *)malloc(sizeof(struct node));


    if (head == NULL )
    {
        printf("Null Nodes");

    }
    else
    {
        ptr1 = ptr2 = head;

        int count = 1;
        while (count != x)
        {
            ptr1 = ptr1->next;
            count++;

        }



        int count2 = 1;
        while (count2 != y)
        {
            ptr2 = ptr2->next;
            count2++;   

        }       


        ptr1->next->prev = ptr2;
        ptr1->prev->next = ptr2;
        ptr2->next->prev = ptr1;
        ptr2->prev->next = ptr1;

    temp->prev = ptr1->prev;
    ptr1->prev = ptr2->prev;
    ptr2->prev = temp->prev;

    temp->next = ptr1->next;
    ptr1->next = ptr2->next;
    ptr2->next = temp->next;


    }
    return 0;
}

当我运行这个程序时,如果是第一个和第二个节点,它会崩溃。而在任何其他节点的情况下,它会提供无限循环输出。 (例如:- 2->4 2->4 2->4....等等)`。

我知道还有一些关于节点交换的问题,但我没有找到与我的问题类似的问题。请帮帮我..!!

提前致谢。

【问题讨论】:

  • 至于错误,请考虑您从未更新head 指针的事实。这应该是寻找漏诊病例的良好开端。
  • 考虑用你的函数成功地交换位置 1 和 3(如果它工作的话)。 (head) -> (2) -> (3) -> (3) -> (2) -> (head) ptrhead 可能指向同一个内存位置,但它们不是同一个变量。
  • 此外,交换代码不需要分配内存(您不会在代码中释放内存)。交换节点仅意味着您重新排列现有指针。您可能需要临时存储指针,但不需要临时存储节点。
  • @Sujit 哇,你有没有看过接受的答案?
  • @Sujit 我认为您最终会得到一个节点,其中 next 指针指向同一个节点,例如ptr2->next = ptr2。当您到达这样一个节点时,输出函数将在该节点上永远循环。

标签: c swap doubly-linked-list


【解决方案1】:

如果 ptr1 == head (ptr1->prev == NULL) 或 ptr2 == head (ptr2->prev == NULL),代码将失败,因为它最终会尝试使用 head->next,这不会不存在。还需要检查列表的结尾,如果 ptr1->next == NULL 或 ptr2->next == NULL,可以使用本地尾指针来处理。使用指向节点的指针可以简化代码。例如,指向 ptr1 的下一个指针的指针可以是 &ptr1->prev->next 或 &head。指向 ptr2 的 prev 指针可以是 &ptr2->next->prev 或 &tail(并设置 tail = ptr2)。

使用指向节点的指针解决了交换相邻节点的问题。 temp 也可以是指向节点的指针。

使用指向节点(而不是计数)的指针进行交换的示例代码:

typedef struct node NODE;
/* ... */
NODE * SwapNodes(NODE *head, NODE *ptr1, NODE *ptr2)
{
NODE **p1pn;            /* & ptr1->prev->next */
NODE **p1np;            /* & ptr1->next->prev */
NODE **p2pn;            /* & b->prev->next */
NODE **p2np;            /* & b->next->prev */
NODE *tail;             /* only used when x->next == NULL */
NODE *temp;             /* temp */
    if(head == NULL || ptr1 == NULL || ptr2 == NULL || ptr1 == ptr2)
        return head;
    if(head == ptr1)
        p1pn = &head;
    else
        p1pn = &ptr1->prev->next;
    if(head == ptr2)
        p2pn = &head;
    else
        p2pn = &ptr2->prev->next;
    if(ptr1->next == NULL){
        p1np = &tail;
        tail = ptr1;
    } else
        p1np = &ptr1->next->prev;
    if(ptr2->next == NULL){
        p2np = &tail;
        tail = ptr2;
    }else
        p2np = &ptr2->next->prev;
    *p1pn = ptr2;
    *p1np = ptr2;
    *p2pn = ptr1;
    *p2np = ptr1;
    temp = ptr1->prev;
    ptr1->prev = ptr2->prev;
    ptr2->prev = temp;
    temp = ptr1->next;
    ptr1->next = ptr2->next;
    ptr2->next = temp;
    return head;
}

【讨论】:

  • 已经尝试重新排列顺序......仍然,结果是一样的:(
  • ptr1->next->prev = ptr2; ptr1->prev->next = ptr2; ptr2->下一个->上一个 = ptr1; ptr2->prev->next = ptr1; temp->prev = ptr1->prev; ptr1->prev = ptr2->prev; ptr2->prev = temp->prev;临时->下一个 = ptr1->下一个; ptr1->下一个 = ptr2->下一个; ptr2->next = temp->prev;临时->数据=ptr1->数据; ptr1->数据= ptr2->数据; ptr2->data = temp->data;
  • @Sujit - 我更新了我的答案以显示双指针(指向指针的指针)的用法。问题是代码覆盖了相邻节点的 next 和 prev。我不明白为什么你在不相邻的节点上遇到了麻烦。当您在 ptr1 和 ptr2 之间交换时,双指针不会被覆盖。
  • 谢谢。它适用于头/尾以外的节点。我会尝试向它添加该异常。
  • @Sujit - 我之前不得不离开,所以我添加了显示头/尾处理的代码。
【解决方案2】:

这可以压缩,但如果你有问题,它可以帮助详细说明。

typedef struct node Node;

void link( Node* a, Node* b )
{
    a->next = b;
    b->prev = a;
}

void swap_nodes( Node* a, Node* b )
{
    if(a==b) return; // don't swap with yourself

    // handle adjacent nodes separately
    if( a->next == b )
    {
        Node* bef = a->prev;
        Node* aft = b->next;
        link( bef, b);    // link bef, b, a, aft
        link( b, a );
        link( a, aft );
    }
    else if( b->next == a )
    {
        Node* bef = b->prev;
        Node* aft = a->next;
        link( bef, a);   // link bef, a, b, aft
        link( a, b );
        link( b, aft );
    }
    else
    {
        Node* a_prv = a->prev;
        Node* a_nxt = a->next;
        Node* b_prv = b->prev;
        Node* b_nxt = b->next;

        link( a_prv, b ); link( b, a_nxt ); // links b in a's old position
        link( b_prv, a ); link( a, b_nxt ); // links a in b's old position
    }
}

还要注意,你的头节点不应该是null,它应该是一个哨兵节点,如果你的列表是空的,它会链接到它自己。这意味着永远不会有第一个节点,也没有最后一个节点,列表也永远不会为空。这消除了大量的特殊情况。见here

【讨论】:

  • 您的意思是“还注意您的头部节点...”吗?
  • 10 次调用函数链接......这对我来说非常困惑......我稍后会尝试这种方式。感谢您的宝贵时间。
猜你喜欢
  • 2017-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
相关资源
最近更新 更多