benhpark
benhpark

Reputation: 37

Trouble with overloaded operator<< function in circular list

I am working on a program that reads in a polynomial as input, outputs the polynomial, evaluating the polynomial, and adding two polynomials while maintaining a circularly linked list. An analysis using gdb revealed that there is a problem with the Next() member function of CircListIterator class template. What could I be doing wrong with Next()? The code and the output are reproduced below. I apologize for the long code.


main.cpp

#include <iostream>
#include "Polynomial.h"

int main() {
    Polynomial poly1, poly2;
    Polynomial result;

    std::cout << "Enter the first polynomial (format: number_of_terms coef1 expon1 coef2 expon2 ...): ";
    std::cin >> poly1;
    std::cout << "Polynomial 1: " << poly1 << std::endl;
    
    std::cout << "Enter the second polynomial (format: number_of_terms coef1 expon1 coef2 expon2 ...): ";
    std::cin >> poly2;
    std::cout << "Polynomial 2: " << poly2 << std::endl;

    float x = 2.0;  // Example value for x
    std::cout << "Value of Polynomial 1 at x = " << x << " is: " << poly1.Evaluate(x) << std::endl;
    std::cout << "Value of Polynomial 2 at x = " << x << " is: " << poly2.Evaluate(x) << std::endl;
    
    result = poly1 + poly2;
    std::cout << "Sum: " << result << std::endl;
    std::cout << "Value of Sum Polynomial at x = " << x << " is: " << result.Evaluate(x) << std::endl;

    return 0;
}

Term.h

#ifndef TERM_H
#define TERM_H

struct Term {
    int coef;
    int expon;
    void Init(int c, int e) { coef = c; expon = e; }
};

#endif // TERM_H

ListNode.h

#ifndef LISTNODE_H
#define LISTNODE_H

template <class Type> class CircList;
template <class Type> class CircListIterator;

template <class Type>
class ListNode {
    friend class CircList<Type>;
    friend class CircListIterator<Type>;

    template <class T>
    friend std::ostream& operator<<(std::ostream& os, const CircList<T>& list);

private:
    Type data;
    ListNode *link;

public:
    ListNode(Type element = 0, ListNode *next = nullptr) : data(element), link(next) {}
};

#endif // LISTNODE_H

CircList.h

#ifndef CIRCLIST_H
#define CIRCLIST_H

#include <iostream>
#include "ListNode.h"

template <class Type> class CircListIterator;

template <class Type>
class CircList {
    friend class CircListIterator<Type>;

private:
    ListNode<Type> *last;

public:
    static ListNode<Type>* av;
    CircList() : last(nullptr) {}
    ~CircList();

    void RetNode(ListNode<Type>* x);
    ListNode<Type> *GetNode();
    ListNode<Type> *getFirst() const;
    ListNode<Type> *getLast() const;
    ListNode<Type> *Insert(ListNode<Type> *x, Type i);
    void Delete(ListNode<Type> *x);
    void Attach(const Type &item);
};

template <class Type>
ListNode<Type>* CircList<Type>::av = nullptr;

template <class Type>
std::ostream& operator<<(std::ostream& os, const CircList<Type>& list);

// Include the implementation here
#include "CircList.cpp"

#endif // CIRCLIST_H


CircList.cpp

#ifndef CIRCLIST_CPP
#define CIRCLIST_CPP

#include "CircList.h"

template <class Type>
ListNode<Type>* CircList<Type>::GetNode() {
    ListNode<Type>* x;
    if (!av) x = new ListNode<Type>;
    else { x = av; av = av->link; }
    return x;
}

template <class Type>
void CircList<Type>::RetNode(ListNode<Type>* x) {
    x->link = av;
    av = x;
}

template <class Type>
CircList<Type>::~CircList() {
    if (last != nullptr) {
        ListNode<Type>* current = last->link;
        while (current != last) {
            ListNode<Type>* temp = current;
            current = current->link;
            delete temp;
        }
        delete last;
    }
}

template <class Type>
ListNode<Type> *CircList<Type>::getFirst() const {
    if (last == nullptr) return nullptr;
    else return last->link;
}

template <class Type>
ListNode<Type> *CircList<Type>::getLast() const {
    return last;
}

template <class Type>
ListNode<Type> *CircList<Type>::Insert(ListNode<Type> *x, Type i) {
    if (last == nullptr) {
        last = new ListNode<Type>(i);
        last->link = last;
        return last;
    }
    ListNode<Type> *temp = new ListNode<Type>(i, x->link);
    x->link = temp;
    if (x == last) {
        last = temp;
    }
    return temp;
}

template <class Type>
void CircList<Type>::Delete(ListNode<Type> *x) {
    if (last == nullptr) {
        std::cout << "The list is empty" << std::endl;
        return;
    }
    if (last->link == last && last == x) {
        delete last;
        last = nullptr;
        return;
    }
    ListNode<Type> *temp = last->link;
    ListNode<Type> *prev = last;
    do {
        if (temp == x) {
            prev->link = temp->link;
            if (x == last) {
                last = prev;
            }
            if (x == last->link) {
                last->link = x->link;
            }
            delete x;
            return;
        }
        prev = temp;
        temp = temp->link;
    } while (temp != last->link);

    std::cout << "Node not found" << std::endl;
}

template <class Type>
void CircList<Type>::Attach(const Type &item) {
    ListNode<Type>* newNode = new ListNode<Type>(item);
    if (last == nullptr) {
        last = newNode;
        last->link = last;
    } else {
        newNode->link = last->link;
        last->link = newNode;
        last = newNode;
    }
    std::cout << "Term with Exponent " << item.expon 
              << " and coefficient " << item.coef << " added. " << std::endl;
}

#endif // CIRCLIST_CPP


CircListIterator.h

#ifndef CIRCLISTITERATOR_H
#define CIRCLISTITERATOR_H

#include "CircList.h"

template <class Type>
class CircListIterator {
public:
    CircListIterator(const CircList<Type> &l);
    Type getData();
    bool NotNull() const;
    bool NextNotNull() const;
    Type* First();
    Type* Next();
    bool IsEmpty() const;
    ListNode<Type>* CurrentPosition() const;

private:
    const CircList<Type> &list;
    ListNode<Type> *current;
};

// Include the implementation here
#include "CircListIterator.cpp"

#endif // CIRCLISTITERATOR_H

CircListIterator.cpp

#ifndef CIRCLISTITERATOR_CPP
#define CIRCLISTITERATOR_CPP

#include "CircListIterator.h"

template <class Type>
CircListIterator<Type>::CircListIterator(const CircList<Type> &l)
    : list(l), current(l.getFirst()) {}

template <class Type>
Type CircListIterator<Type>::getData() {
    return current->data;
}

template <class Type>
bool CircListIterator<Type>::NotNull() const {
    return current != nullptr ? true : false;
}

template <class Type>
bool CircListIterator<Type>::NextNotNull() const {
    return current != nullptr && current->link != nullptr ? true : false;
}

template <class Type>
Type* CircListIterator<Type>::First() {
    current = list.getFirst();
    if (current && current->data.expon == -1) {
        current = current->link;
        if (current == list.getFirst()) {
            current = nullptr;
        }
    }
    return current ? &current->data : nullptr;
}

template <class Type>
Type* CircListIterator<Type>::Next() {
    if (current) {
        current = current->link;
        if (current && (current->data.expon == -1 || current == list.getFirst())) {
            current = nullptr;
        }
        return current ? &current->data : nullptr;
    }
    return nullptr;
}

template <class Type>
bool CircListIterator<Type>::IsEmpty() const {
    const ListNode<Type>* first = list.getFirst();
    return first == nullptr || (first->data.expon == -1 && first->link == first);
}

template <class Type>
ListNode<Type>* CircListIterator<Type>::CurrentPosition() const {
    return current;
}

#endif // CIRCLISTITERATOR_CPP

Polynomial.h

#ifndef POLYNOMIAL_H
#define POLYNOMIAL_H

#include "CircList.h"
#include "Term.h"
#include "CircListIterator.h"

class Polynomial {
    friend std::istream& operator>>(std::istream&, Polynomial&);
    friend std::ostream& operator<<(std::ostream&, const Polynomial&);
    friend Polynomial operator+(const Polynomial&, const Polynomial&);

private:
    CircList<Term> poly;

public:
    Polynomial() : poly() {}
    Polynomial(const Polynomial& other);
    const Polynomial& operator=(const Polynomial& a);
    ~Polynomial();
    float Evaluate(float x);
};

#endif // POLYNOMIAL_H

Polynomial.cpp

#include <iostream>
#include <cmath>
#include "Polynomial.h"

Polynomial::Polynomial(const Polynomial& other) : poly() {
    CircListIterator<Term> iter(other.poly);
    const Term* t = iter.First();
    while (t != nullptr) {
        poly.Attach(*t);
        t = iter.Next();
    }
}

const Polynomial& Polynomial::operator=(const Polynomial& a) {
    if (this != &a) {  // Check for self-assignment
        // Clean up existing polynomial
        CircListIterator<Term> iter(poly);
        Term* t = iter.First();
        while (t != nullptr) {
            poly.Delete(iter.CurrentPosition());
            t = iter.Next();
        }

        // Copy the polynomial 'a'
        CircListIterator<Term> aIter(a.poly);
        const Term* aTerm = aIter.First();
        while (aTerm != nullptr) {
            poly.Attach(*aTerm);
            aTerm = aIter.Next();
        }
    }
    return *this;
}

Polynomial::~Polynomial() {
    CircListIterator<Term> iter(poly);
    Term* t = iter.First();
    while (t != nullptr) {
        poly.Delete(iter.CurrentPosition());
        t = iter.Next();
    }
}

Polynomial operator+(const Polynomial& a, const Polynomial& b) {
    CircListIterator<Term> Aiter(a.poly);
    CircListIterator<Term> Biter(b.poly);
    Polynomial c;
    Term *p = Aiter.First();
    Term *q = Biter.First();
    Term temp;

    while (p != nullptr || q != nullptr) {
        if (p == nullptr) {
            std::cout << "Attaching q: coef=" << q->coef << ", expon=" << q->expon << std::endl;
            temp.Init(q->coef, q->expon);
            c.poly.Attach(temp);
            q = Biter.Next();
        } else if (q == nullptr) {
            std::cout << "Attaching p: coef=" << p->coef << ", expon=" << p->expon << std::endl;
            temp.Init(p->coef, p->expon);
            c.poly.Attach(temp);
            p = Aiter.Next();
        } else if (p->expon == q->expon) {
            std::cout << "Summing: p->coef=" << p->coef << ", q->coef=" << q->coef << std::endl;
            int sum = p->coef + q->coef;
            if (sum != 0) {
                temp.Init(sum, p->expon);
                c.poly.Attach(temp);
            }
            p = Aiter.Next();
            q = Biter.Next();
        } else if (p->expon > q->expon) {
            std::cout << "Attaching p: coef=" << p->coef << ", expon=" << p->expon << std::endl;
            temp.Init(p->coef, p->expon);
            c.poly.Attach(temp);
            p = Aiter.Next();
        } else {
            std::cout << "Attaching q: coef=" << q->coef << ", expon=" << q->expon << std::endl;
            temp.Init(q->coef, q->expon);
            c.poly.Attach(temp);
            q = Biter.Next();
        }
    }

    return c;
}

std::istream& operator>>(std::istream& is, Polynomial& x) {
    int n, coef, expon;
    Term temp;
    
    x.poly = CircList<Term>();  // Clear existing polynomial

    temp.Init(0, -1);  // Create head node with exponent -1
    x.poly.Attach(temp);

    is >> n;  // Read number of terms

    for (int i = 0; i < n; i++) {
        is >> coef >> expon;
        if (coef != 0) {  // Ignore terms with zero coefficients
            temp.Init(coef, expon);
            x.poly.Attach(temp);
        }
    }
    return is;
}

std::ostream& operator<<(std::ostream& os, const Polynomial& p) {
    CircListIterator<Term> iter(p.poly);
    const Term* t = iter.First();
    
    if (t == nullptr) {
        os << "0";
        return os;
    }

    bool firstTerm = true;
    while (t != nullptr) {
        if (t->expon != -1) {
            if (!firstTerm) {
                os << (t->coef > 0 ? " + " : " - ");
            } else {
                if (t->coef < 0) {
                    os << "-";
                }
                firstTerm = false;
            }

            int absCoef = std::abs(t->coef);
            if (absCoef != 1 || t->expon == 0) {
                os << absCoef;
            }

            if (t->expon != 0) {
                os << "x";
                if (t->expon != 1) {
                    os << "^" << t->expon;
                }
            }
        }
        t = iter.Next();
    }

    return os;
}

float Polynomial::Evaluate(float x) {
    float result = 0.0;
    CircListIterator<Term> iter(poly);
    const Term* t = iter.First();
    
    while (t != nullptr) {
        result += t->coef * std::pow(x, t->expon);
        t = iter.Next();
    }
    
    return result;
}

Output:

Enter the first polynomial (format: number_of_terms coef1 expon1 coef2 expon2 ...): Term with Exponent -1 and coefficient 0 added. 
3 1 2 2 1 1 0
Term with Exponent 2 and coefficient 1 added. 
Term with Exponent 1 and coefficient 2 added. 
Term with Exponent 0 and coefficient 1 added. 
Polynomial 1: x^2 + 2x + 1
Enter the second polynomial (format: number_of_terms coef1 expon1 coef2 expon2 ...): Term with Exponent -1 and coefficient 0 added. 
3 1 2 3 1 2 0
Term with Exponent 2 and coefficient 1 added. 
Term with Exponent 1 and coefficient 3 added. 
Term with Exponent 0 and coefficient 2 added. 
Polynomial 2: x^2 + 3x + 2
Value of Polynomial 1 at x = 2 is: 9
Value of Polynomial 2 at x = 2 is: 12
Summing: p->coef=1, q->coef=1
Term with Exponent 2 and coefficient 2 added. 
Summing: p->coef=2, q->coef=3
Term with Exponent 1 and coefficient 5 added. 
Summing: p->coef=1, q->coef=2
Term with Exponent 0 and coefficient 3 added. 
Term with Exponent 2 and coefficient 2 added. 
Term with Exponent 1 and coefficient 5 added. 
Term with Exponent 0 and coefficient 3 added.

Program received signal SIGSEGV, Segmentation fault.
0x000055555555657b in CircListIterator<Term>::Next (this=0x7fffffffeb10) at /home/CircListIterator.cpp:42

Upvotes: 0

Views: 79

Answers (0)

Related Questions