操作链表函数的逻辑错误

Logic Error With Function to Manipulate Linked List

我需要帮助来确定我的逻辑错误在哪里。我正在用 C++ 编写一个函数,该函数将单链表作为输入,旨在删除奇数整数节点,同时复制偶数整数节点:

示例:

initial: 0  5  2  2  7  3  7  9  0  2
 ought2b: 0  0  2  2  2  2  0  0  2  2  
outcome: 0  0  2  2  2  2  0  0  2  2  

initial: 0
 ought2b: 0  0

initial: 1
 ought2b: (empty)

我遇到的问题是我的结果是正确的(如上所示)但是在第二个链表之后整个程序退出并且我得到一个退出代码 11 当我只能假设是一个分段错误时。我已经将整个函数重写了 6 次以上,并且在精神上找不到我在哪里犯了逻辑错误,因为我的代码通常在每次迭代中看起来都相似。任何帮助将不胜感激!功能代码如下所示。

void RemOddDupEven(Node*& headPtr){
    // Define two cursors to iterate through referenced list.
    Node *precursor = 0,
            *cursor = headPtr;

    // Error Checking | Check for reference to empty list.
    if(headPtr == 0){
        cerr << "RemOddDupEven() attempted on empty list" << endl;
        return;
    }

    while(cursor->link != 0){
        if(cursor->data%2 != 0){
            /// Odd node found in referenced list. Remove it.
            if(precursor == 0){
                // No previous. Removing first node.
                precursor = cursor;
                cursor = cursor->link;
                headPtr = cursor;
                delete precursor;
                precursor = 0;
            } else {
                Node* tempNodePtr = cursor;
                cursor = cursor->link;
                precursor->link = cursor;
                delete tempNodePtr;
            }
        } else {
            /// Even node found in referenced list. Duplicate it.
            if(precursor == 0){
                // No previous. Duplicate and insert before current node.
                Node* newNodePtr = new Node;
                newNodePtr->data = cursor->data;
                newNodePtr->link = cursor;
                headPtr = newNodePtr;
                precursor = cursor;
                cursor = cursor->link;
            } else {
                // There is a previous. Duplicate and insert before current.
                Node* newNodePtr = new Node;
                newNodePtr->data = cursor->data;
                precursor->link = newNodePtr;
                newNodePtr->link = cursor;
                precursor = cursor;
                cursor = cursor->link;
            }
        }

    }
    /// We are at last item in the list.
    if(cursor->data%2 != 0){
        /// Odd node found at end of referenced list. Remove it.
        precursor->link = 0;
        delete cursor;
        cursor = 0;
    } else {
        /// Even node found at the end of referenced list. Duplicte it.
        Node* newNodePtr = new Node;
        newNodePtr->data = cursor->data;
        precursor->link = newNodePtr;
        newNodePtr->link = cursor;
    }
}

你的函数太复杂,函数内部有很多特殊条件,很难研究。

但乍一看很明显,例如这个代码片段

/// We are at last item in the list.
if(cursor->data%2 != 0){
    /// Odd node found at end of referenced list. Remove it.
    precursor->link = 0;
    delete cursor;
    cursor = 0;
} else {

错了。

让我们考虑一个只有一个节点是头节点的列表。

在这种情况下循环

while(cursor->link != 0){
    //...
}

不会被执行,因为headPtr->link等于nullptr。这也意味着 precursor 等于 0(它在循环之前最初设置为 0)。所以表达式语句

precursor->link = 0;

导致函数出现未定义的行为。

同时这条语句

    cursor = 0;

不会更改 headPtr 的值,因为 cursorheadPtr 是两个不同的对象,更改一个对象的值不会影响另一个对象的值。

函数实现看起来更简单。

这是一个演示程序

#include <iostream>

struct Node
{
    int data;
    Node *link;
};

void initialize(Node * &head, const int a[], size_t n)
{
    Node **current = &head;

    while (*current) current = &(*current)->link;

    for (size_t i = 0; i < n; i++)
    {
        *current = new Node{ a[i], nullptr };
        current = &(*current)->link;
    }
}

void RemOddDupEven(Node * &head)
{
    Node **current = &head;

    while (*current)
    {
        if ((*current)->data % 2 == 0)
        {
            (*current)->link = new Node{ (*current)->data, (*current)->link };
            current = &(*current)->link->link;
        }
        else
        {
            Node *tmp = *current;
            *current = (*current)->link;
            delete tmp;
        }
    }
}

std::ostream & show(Node * &head, std::ostream &os = std::cout)
{
    for (Node *current = head; current; current = current->link)
    {
        os << current->data << ' ';
    }

    return os;
}

int main()
{
    Node *head = nullptr;
    int a[] = { 0, 5, 2, 2, 7, 3, 7, 9, 0, 2 };

    initialize(head, a, sizeof(a) / sizeof(*a));

    show(head) << std::endl;

    RemOddDupEven(head);

    show(head) << std::endl;

    return 0;
}

它的输出是

0 5 2 2 7 3 7 9 0 2
0 0 2 2 2 2 0 0 2 2