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

时间:2014-10-04 07:36:55

标签: c++ pointers struct linked-list nodes

我正在尝试编写将遍历链表的函数,其中节点表示多项式的项。每个节点包括系数字段(双重命名系数),功率(size_t命名功率)和链接(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");
    }
}

2 个答案:

答案 0 :(得分:2)

这是一系列明确错误的假设,说明如何在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引用一样, nothing 会让你在C / C ++程序中遇到麻烦,而不是指针管理不当。
  • 该算法不保持列表订购的授权。

您的代码更改

  • 您的代码要求 ordered 列表的要求得以维护,但您的系数插入算法不会尝试满足该要求。如果找不到匹配的指数,则setCoeff成员需要插入新术语,如果保持排序,您将通过适当的枚举知道是否通过发现(a)超出您的指数,或者(b)清单的结尾,以先发生者为准
  • isize_t值,表示对象计数是幅度。标准任务size_t无符号,这意味着它不能为负数。这意味着检查i >= 0是没用的。 总是就是这样。
  • 在知道需要之前分配新节点。请记住,如果找到匹配的指数条目,则应该更新现有的节点。只有在 no 匹配时才需要新节点。
  • 您的首次插入检测需要完整的重新启动。保证可以调用未定义的行为。

首先让自己更轻松。提供一个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;
    }
}

我真诚地希望它有所帮助,并希望您在到达The Good Stuff之前彻底挖掘残骸。它最终值得。

答案 1 :(得分:1)

我会使用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功率值和正功率值。