使用链表添加多项式?帮助

时间:2018-04-17 04:56:52

标签: c++ pointers

欢迎阅读此内容的任何人。我对这个程序的问题是我似乎不理解如何将2个多项式顺序输入到链表中。我可以添加新的多项式或读取当前输入的多项式,但加法和减法给了我一些问题。这是我现在拥有的:

#include <iostream>
#include <cmath>
#include <cstddef>

using namespace std;

typedef float polyType;

struct polyInfo
{
int number;
int power;
polyInfo* link;
};

//typedef polyInfo* polyPtr;
//polyPtr head;
//polyPtr currPtr;
//polyPtr newNodePtr;

class Polynomial
{
private:
    polyInfo *head;
    int maxpow = 0;
public:
    Polynomial(){}

    void createPoly(int n, int p)
    {
        polyInfo *temp = new polyInfo();
        temp->power = p;
        temp->number = n;
        temp->link = head;
        head = temp;
        if (maxpow < p)
        {
            maxpow = p;
        }
    }

    void getPoly()
    {
        polyInfo *temp = head;
        while (temp != NULL)
        {
            if (temp->number != 0)
            {
                cout << temp->number << "x^" << temp->power << " ";
            }
            temp = temp->link;
        }
        cout << "\n";
    }

    void addPoly()
    {
        polyInfo *temp = head;
        while (temp != NULL)
        {
            if (temp->number != 0)
            {
                polyInfo *temp2 = head;
                temp2 = temp2->link;
                if (temp2->link != NULL)
                {
                    if (temp->power == temp2->power)
                    {
                        temp->number = (temp->number)+(temp2->number);
                        temp2->number = 0;
                        temp = temp->link;
                    }
                }
                else
                {
                    temp = NULL;
                }
            }
        }
    }

    void subtractPoly()
    {}
};

int main()
{
    int menuNum;//used to see which menu option user chooses
    int mainPower;
    int mainNumber;

    Polynomial mainPoly;
    bool menu = true;

    while (menu)
   {
       cout << "Enter 1 to create new polynomial"
            << "\nEnter 2 to read a polynomial"
            << "\nEnter 3 to add polynomials"
            << "\nEnter 4 to subtract polynomials"
            << "\nEnter 5 to end program :";
       cin >> menuNum;

       switch(menuNum)
       {
           case 1:
                  cout << "\nEnter the coefficient: ";
                  cin >> mainNumber;
                  cout << "\nEnter the exponent of X: ";
                  cin >> mainPower;
                  mainPoly.createPoly(mainNumber,mainPower);
                  break;
           case 2:
                  mainPoly.getPoly();
                  break;
           case 3:
                  mainPoly.addPoly();
                  break;
           case 4:
                  mainPoly.subtractPoly();
                  break;
           case 5:
                  cout << "End of program\n";
                  menu = false;
           default:
                  cout << "\nInvalid Input, please try again\n\n";
                  break;
       }
    }
    return 0;
}

我为代码中几乎没有任何评论而道歉。我通常会回过头来添加它们。我在main中运行一个菜单,允许您输入一个新的多项式,读出它们,添加它们或减去它们。我有输入新的方法并将其读出给用户的方法。我已经在我的添加代码上得到了这么多,它不起作用。但问题不能通过两个单独的列表来解决,这是我在网上发现的大部分内容。它必须通过一个列表来完成,该列表包含每个节点中的数字和功率。

1 个答案:

答案 0 :(得分:2)

首先:您正在处理用户输入,这些输入始终无效!如果用户输入e。 G。 x7operator>>将失败并且cin将保持错误状态(使后续流操作也失败),因此您将陷入无休止的循环中再次执行同一任务再次,取决于最后的成功输入。如果第一个用户输入无效,则根本不会初始化menuItem,因此您甚至会遇到未定义的行为!所以:

if(std::cin >> menuItem)
{
    // good case
}
else
{
    // bad case!
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

最小处理:清除错误状态并忽略导致它的输入,在下一个循环中启动新的。您可以另外告知用户他/她做了什么......

首选适当的名称:getPoly将多项式打印到控制台,然后将其重命名为printPoly。同样,您的addPoly函数看起来更像normalize函数(如果有,但需要一些修复......)。

如果你真的想添加多项式,那么你需要两个!然后你需要决定:你想要将其他多项式添加到当前的多项式,还是要创建一个包含结果的新多项式?这将影响界面......您可能想要创建两者。请注意,对于这些操作,有默认的函数名称:operator+operator+=。如果实现这些,您可以编写如下代码:

Polynomial x, y;
Polynomial z = x + y;
x += y;

现在,您似乎允许以任意顺序存储多项式元素。这将要求您在加法和减法时依赖O(n²)算法。这不是一个好主意......更好:保持多项式归一化为以下含义:

  • 如果number为0,则不要存储元素。如果一个元素在操作期间变为null,则将其删除。
  • 保持元素排序,加法和减法以这种方式获得线性复杂性,如果第一个元素是最大元素,你甚至可以省略maxpow成员(它相当于head->power)。

综上所述,我推荐另一个界面。之后的用法将是:

// create an initial polynomial:
Polynomial x(1, 3);
x += Polynomial(2, 2);
x += Polynomial(3, 1);
x.print();
// output: 3x^1 + 2x^2 + 3x^1

以下代码不完整,您需要自己贡献一些附加内容(例如,PolyInfo结构的适当构造函数;顺便说一下:将此内容作为内部类!)... < / p>

Polynomial(int n = 0, int p = 0)
    : head(nullptr)
{
    if(n)
    {
        head = new PolyInfo(n, p);
    }
}

static Polynomial operator+(Polynomial const& x, Polynomial const& y)
{
    PolyInfo* result;
    PolyInfo* tmp = nullptr;
    PolyInfo* ix = x.head;
    PolyInfo* iy = y.head;
    while(ix || iy)
    {
        if(ix && (!iy || ix->power > iy->power))
        {
            result = new PolyInfo(*ix);
            ix = ix->link;
        }
        else if(iy && (!ix || iy->power > ix -> power))
        {
            result = new PolyInfo(*iy);
            iy = iy->link;
        }
        else
        {
            int n = ix->number + iy->number;
            ix = ix->link;
            iy = iy->link;
            if(n == 0)
                // ignore this node!!!
                continue;
            result = new PolyInfo(n, ix->power);
        }
        result->link = tmp;
        tmp = result;
    }
    // yet in  r e v e r s e  order!
    result = nullptr;
    while(tmp)
    {
        PolyInfo* next = tmp->link;
        tmp->link = result;
        result = tmp;
        tmp = next;
    }
}

Polynomial& operator+=(Polynomial const& other)
{
    *this = *this + other;
    return *this;
}

第一步完成......

非常确定您不想为operator-重复此代码,因此我们可能有一个共同的功能,因此,将当前的operator+设为私有并重命名,并添加其他参数:< / p>

static Polynomial calculate
(
    Polynomial const& x, Polynomial const& y,
    int(*op)(int, int)
)
{ /* ... */ }

现在还有一条线要改变(在两个节点功率相等的情况下):

int n = op(ix->number, iy->number);

现在添加两个新运算符:

static Polynomial operator+(Polynomial const& x, Polynomial const& y)
{
    return calculate(x, y, [](int x, int y) { return x + y; });
}
static Polynomial operator-(Polynomial const& x, Polynomial const& y)
{
    return calculate(x, y, [](int x, int y) { return x - y; });
}

现在,为了这个工作,我们还需要一个复制构造函数和复制赋值,以防止内存泄漏;析构函数(参见rule of three)(但见下文!!!):

Polynomial(Polynomial const& other)
{
    // make a deep copy by copying all elements
    // easiest is creating the copy in inverse order and
    // then reverting it similar as in calculate
    // have a common function for then!
}

Polynomial& operator=(Polynomial const& other)
{
    this->~Polynomial();
    new(this)Polynomial(other);
    return *this;
}

好的,上面的赋值运算符异常且效率低(但至少不正确,并且很容易实现......),它会删除当前对象并通过复制构造函数重新创建它。这将导致删除所有节点并根据需要重新创建它们。更好:重用已经存在的节点,将值从另一个多项式复制到。然后在另一个中创建更多的副本,或者删除当前存在的更多副本。将此作为练习。但是,您可以在复制构造函数中使用它:

Polynomial(Polynomial const& other)
    : Polynomial()
{
    *this = other;
}

析构函数只会删除所有存在的节点。

完整性:Rule of five ...

这不是必须的,但提供了很好的优化机会:

Polynomial(Polynomial&& other)
    : Polynomial()
{
    std::swap(this->head, other->head);
    // swaps nullptr into other...
}

Polynomial& operator=(Polynomial&& other)
{
    std::swap(this->head, other->head);
    // huh, memory leak?
    // no, other will delete contents previously owned by this
    // as soon as running out of scope...
    return *this;
}

这看起来像是一个练习任务,因此您可能不被允许,但如果您是,请使用STL容器而不是您自己的链接列表:e。 G。 std::list用于双向链接列表(使迭代更容易,特别是避免以逆序创建并在之后还原),std::forward_list用于单个链接列表,甚至std::vector。这将使您从上面的所有内存管理中解脱出来,并且默认的复制/移动构造函数/赋值和析构函数适合您(因为相应的容器等价物将被隐式调用)...

最后:以上所有代码都是未经测试的,可能存在错误,但它应该为您指明方向。