我的双链表交换函数有什么问题吗?

Is anything wrong with my doubly linked list swap function?

本文关键字:什么 问题 函数 链表 交换 我的      更新时间:2023-10-16

我有一个用于交换2个节点的函数:

void swap(Node<T>* a, Node<T>* b) {
    if(a->m_prev)
        a->m_prev->m_next = b;
    if(b->m_prev)
        b->m_prev->m_next = a;
    if(a->m_next)
        a->m_next->m_prev = b;
    if(b->m_next)
        b->m_next->m_prev = a;
    Node<T>* temp;
    temp = a->m_prev;
    a->m_prev = b->m_prev;    
    b->m_prev = temp;
    temp = a->m_next;
    a->m_next = b->m_next;    
    b->m_next = temp;
}

然而,当使用我的递归选择sort:

void selectionSort(Node<T>* head) {
    if(next(head) == NULL) {
        return;
    }
    Node<T>* minimum = min(head);
    swap(head,minimum);
    selectionSort(minimum->m_next);
}

大约在排序的中途,它将我的一个节点的下一个指针设置为NULL,然后当我打印我的列表时,它被正确地排序到该值,但其余的丢失,因为指针被错误地设置为NULL。

我检查过了,

我的初始列表是正确的,没有错误连接的节点。

我的swap函数只在非空的有效节点上调用。

所以我责怪swap函数。有什么问题吗?

我认为当a在列表中与b相邻时发生问题。例如,如果b->prev指向a(意味着a在列表中恰好在b之前),则行

b->prev->next = a; 

等价于

a->next = a;

这显然不是你想要的

这里有一些关于如何处理在双重链表中交换节点的问题的技巧。待交换的节点A和B称为内部节点。列表中的其他节点是外部节点。离A和/或B较近的外部节点用W、X、Y、z表示。离A、B较远的外部节点用省略号表示。在交换内部节点时,会有2、3或4个外部节点参与交换,如下图

所示。
case 1: widely separated (four external nodes)      ... W A X ... Y B Z ...
case 2: separated by one (three external nodes)     ... W A X B Z ...
case 3: adjacent (two external nodes, A first)      ... W A B Z ...
case 4: adjacent (two external nodes, B first)      ... W B A Z ...

应该可以用一组代码处理前两种情况(在情况2中X同时连接到a和B的事实应该对交换实现没有影响)。如果B在A之前,可以通过交换函数参数来处理后两种情况,这样变量a总是指向第一个节点,变量b总是指向第二个节点。因此,四种情况被简化为两种情况,建模为

cases 1&2:   ... W A X ... Y B Z ...
cases 3&4:   ... W A B Z ...

在情形1&2中,需要更新的内部节点上有4个指针,需要更新的外部节点上有4个指针。在情况3&4中,内部节点上有4个指针需要更新,但外部节点上只有2个指针需要更新。

我建议坐下来用铅笔和纸,首先确定需要更新的指针,然后确定您希望每个指针的最终值是什么。知道了这一点,编码部分应该很容易。

您可以直接交换节点中的值以避免指针灾难

应该可以。

void swap(Node<T>* a, Node<T>* b) {
    if ( a == b )
    {
       return;
    }
    Node<T*> oldANext = a->m_next;
    Node<T*> oldAPrev = a->m_prev;
    Node<T*> oldBNext = b->m_next;
    Node<T*> oldBPrev = b->m_prev;
    // Special case when b is the next of a.
    if ( a->m_next == b )
    {
       a->m_next = oldBNext;
       a->m_prev = b;
       b->m_next = a;
       b->m_prev = oldAPrev;
       if ( oldAPrev )
          oldAPrev->m_next = b;
       if ( oldBNext )
          oldBNext->m_prev = a;
    }
    // Special case when b is the prev of a.
    else if ( a->m_prev == b )
    {
       a->m_prev = oldBPrev;
       a->m_next = b;
       b->m_prev = a;
       b->m_next = oldANext;
       if ( oldANext )
          oldANext->m_prev = b;
       if ( oldBPrev )
          oldBPrev->m_next = a;
    }
    // When a and b are not related.
    else
    {
       a->m_next = oldBNext;
       a->m_prev = oldBPrev;
       b->m_next = oldANext;
       b->m_prev = oldAPrev;
       if ( oldANext )
          oldANext->m_prev = b;
       if ( oldAPrev )
          oldAPrev->m_next = b;
       if ( oldBNext )
          oldBNext->m_prev = a;
       if ( oldBPrev )
          oldBPrev->m_next = a;
    }
}