遍历链表并修改或插入节点C++

Traversing linked list and modifying or inserting node C++

本文关键字:插入 节点 C++ 修改 链表 遍历      更新时间:2023-10-16

我正试图编写一个遍历链表的函数,其中节点表示多项式的项。每个节点包括coefficient(一个双重命名的coeff)、power(一个命名为power的size_t)和link(一个NodePtr*next)的字段。调用该函数时使用一个双变量和一个size_t变量i,前者表示节点应该具有的系数,后者表示其幂。该函数应遍历链表,查找功率i的节点。如果列表中已经包含幂为i的节点,则应更改其系数以保持新值。如果它以前没有幂为i的节点,则应该将该项与系数值相加。列表应按功率排序(即,功率为3的节点应为列表中的节点3)。

以下是我迄今为止写的代码,尽管它目前产生了以下错误:

Project 3.exe中0x0130D2FA处未处理的异常:0xC0000005:写入位置0x0000000C时发生访问冲突。

我不知道为什么会产生错误,所以这是我的第一个问题。第二,我认为我的函数可能存在一些逻辑错误,并且没有正确地修改和创建新节点。

我已经被这个问题困扰了好几天,如果没有这个功能,我就无法测试我的其他功能,所以如果有任何帮助,我们将不胜感激!非常感谢。

void Poly::setCoeff(double value, size_t i)
{
    if (0 <= i){
        Node* prev = new Node();
        Node* curr = new Node();
        Node* newNode = new Node();
        newNode->coeff = value;
        newNode->power = i;
        curr = myHead;      // Initialize curr to myHead;
        if (curr != nullptr)
        {
            while (curr->next != nullptr && curr->power != i)
            {
                prev = curr;
                curr = curr->next;
            }
            if (curr->power == i)
            {
                curr->coeff = value;
            }
            else if (curr->next == nullptr && i == curr->power + 1)
            {
                curr->next = new Node;  // Creates a node at the end of the list
                curr = curr->next; // Points to that node
                curr->next = nullptr; // Prevents it from going any further
                curr->power = i;
                curr->coeff = value;
            }
            else
            {
                prev->next = newNode;
                newNode->next = curr;
            }
        }
        else
        {
            curr->next = newNode;
            curr = curr->next;
        }
    }
    else
    {
        throw std::out_of_range("Index out of range");
    }
}

正是对C++中如何管理动态内存的一系列明显错误的假设让您在这段代码中遇到了大量麻烦。如果这不是一个学术练习,我会告诉你把它全部扔掉,然后使用:

std::map<size_t, double>

也称为:好东西。它将完成您需要此代码完成的所有任务。

但这是学术界。就像学术界的大多数事情一样,它们让你在了解应该如何之前先爬过战壕。因此,我将揭露你的代码中的不足之处,但可以说,一旦你了解了所有这些,你将努力从一开始就不必使用现有的工具。

换句话说,除非有人说我必须使用手工编码的链表实现,否则我会使用上面的地图。你还不能,但要知道它就在那里。


您的代码

你没有包括Node的定义,但我只能假设它看起来像这样:

struct Node
{
    double coeff;
    size_t power;
    Node *next;
};

这是否嵌套在class Poly中(如果是后者,则可能是)同样不清楚。它与这个问题并不完全相关,但在这里提到的是,当在SO上提问时,请提供足够的信息,以最小化可能影响你得到的答案的假设。

有了它,你的代码:

void Poly::setCoeff(double value, size_t i)
{
    if (0 <= i)  // NOTE: not needed, unsigned, will always be i >= 0
    {
        Node* prev = new Node();     // NOTE: wrong. leaks memory.
        Node* curr = new Node();     // NOTE: same as above
        Node* newNode = new Node();  // NOTE: **may** leak (see below)
        newNode->coeff = value;
        newNode->power = i;
        curr = myHead;
        if (curr != nullptr) // OK: check for null good
        {
            // NOTE: should be checking `curr`, not curr->next
            while (curr->next != nullptr && curr->power != i)
            {
                prev = curr;
                curr = curr->next;
            }
            // NOTE: should check curr for NULL first.
            if (curr->power == i)
            {
                curr->coeff = value;
            }
            // NOTE: same here. also, 
            else if (curr->next == nullptr && i == curr->power + 1)
            {
                // NOTE: this code path will leak newNode allocated at the
                //  top of the function.
                curr->next = new Node;
                curr = curr->next;
                curr->next = nullptr;
                curr->power = i;
                curr->coeff = value;
            }
            else
            {
                prev->next = newNode;
                newNode->next = curr;
            }
        }
        else
        {   // NOTE: this is where your mainline fault is coming from. you
            //  just validated curr can be NULL here (and will be on initial)
            curr->next = newNode;
            curr = curr->next;
        }
    }
    // NOTE: this can't happen, as i can never be less than zero
    else
    {
        throw std::out_of_range("Index out of range");
    }
}

以下几点比较明显。

  • 您的内存管理不正确,并且会导致内存泄漏
  • 您的指针管理同样很差。指针与Java引用不同,在C/C++程序中,没有什么东西比不正确的指针管理更快地给您带来麻烦
  • 该算法不维护对列表进行排序的命令

对代码的更改

  • 您的代码要求维护一个有序的列表,但您的系数插入算法不会尝试满足该要求。如果找不到匹配的指数,则setCoeff成员需要插入一个新术语,如果保持排序,则通过正确的枚举,您将通过发现(a)超出您的指数,或(b)列表末尾(以先发生的为准)来知道是否是这种情况
  • isize_t值,这意味着它是用于对象计数的幅度。标准强制size_t无符号,这意味着它不能为负数。这意味着检查i >= 0是无用的。它将总是如此
  • 在知道需要一个节点之前,会分配一个新节点。请记住,如果找到匹配的指数条目,这应该会更新现有节点。只有当没有匹配时,才需要新节点
  • 您的第一次插入检测需要一次完整的重新提取。它保证调用未定义的行为

首先让自己轻松一点。提供一个通过参数设置节点的Node构造函数,这样您就可以停止在该设置中乱丢代码。这样一来,由于您在构造中初始化了所有成员变量,因此读取起来更容易,也更安全。

struct Node
{
    Node *next;
    double coeff;
    size_t power;
    Node(double coeff_, size_t power_, Node *next_=nullptr)
        : coeff(coeff_), power(power_), next(next_)
    {}
};

这样,事情就会变得容易得多。上面的竣工查核事项表可以通过以下更改来实现:

void Poly::setCoeff(double value, size_t i)
{
    Node *prev = nullptr; // points to prior node
    Node *curr = myHead;  // points to current node
    while (curr && curr->power < i)
    {
        prev = curr;         // remember current node...
        curr = curr->next;   // ... then move to next node
    }
    // only allocate a new node if
    //  (a) we reached the end of the list (curr == NULL)
    //  (b) we reached a node with non match (will be larger exponent)
    if (!curr || curr->power != i)
    {
        // **NOW** allocate the new node. we know we need one and we
        //  have a pretty solid idea where it goes.
        Node *newNode = new Node(value, i, curr);
        // if prev is set, then it means the new node goes somewhere
        //  *past* the head pointer otherwise it will become the new head.
        if (prev)
            prev->next = newNode;
        else
            myHead = newNode;
    }
    else
    {   // found matching node
        curr->coeff = value;
    }
}

我真诚地希望它能有所帮助,并祝你在进入《好东西》之前,在困境中度过难关。它最终是值得的。

我将使用std::map(正如WhozCraig的优秀回答所提到的)来跟进答案:

#include <map>
#include <iostream>
typedef std::map<size_t, double> Polynomial;
void AddCoefficientAndPower(Polynomial& poly, double coeff, size_t power)
{
    // This does everything your assignment asked for, except for implementing
    // all of that linked list stuff
    poly[power] = coeff;
}
using namespace std;
int main()
{
    Polynomial myPoly;
    // add the coefficient and power
    AddCoefficientAndPower(myPoly, 3, 1);
    AddCoefficientAndPower(myPoly, 4, 2);
    AddCoefficientAndPower(myPoly, 9, 0);
    AddCoefficientAndPower(myPoly, 6, 3);
    // This one will replace the previous (4,2) 
    AddCoefficientAndPower(myPoly, 3, 2);
    // write out the coefficients followed by the power
    Polynomial::iterator it = myPoly.begin();
    while (it != myPoly.end())
    {
        cout << it->second << "^" << it->first << "n";
        ++it;
    }
}

输出:

9^0
3^1
3^2
6^3

基本上,您的整个赋值是AddCoefficent中的一行C++语句,它在映射中插入一个项,并在存在项的情况下替换现有项。

注意——没有内存泄漏,没有对new的调用,没有崩溃等。

此外,如果您的要求还包括任何积分幂值,则上述方法适用于负、0和正幂值。