Home > Back-end >  Add up those fractions that have a common denominator
Add up those fractions that have a common denominator

Time:05-28

I have a file with fractions. I have to write fractions from it into a structure. Then I need to create a dynamic data structure in order to add those fractions that have a common denominator, but I should not use dynamic arrays. Can you please help me with the fraction addition part? (the link contains a photo of the file with fractions and the result I want to get, but for now I can only display fractions on the screen, but not add them up) enter image description here

#include <iostream>
#include <stdio.h>
#include <Windows.h>
#include <string.h>

using namespace std;

struct fraction {
    int numerator, denominator;
};

struct Node {
    fraction fr;
    Node* next;
};

Node* newNode(fraction fr) {
    Node* p;
    p = new Node;
    p->fr.numerator = fr.numerator;
    p->fr.denominator = fr.denominator;
    p->next = NULL;
    return p;
}

void addNode(Node* curr, Node** head, Node** tail) {
    if (*head == NULL) {
        *head = *tail = curr;
        //        *tail = curr;
    }
    else {
        (*tail)->next = curr;
        *tail = curr;
    }
}

void outList(Node* head) {
    Node* curr;
    curr = head;
    while (curr != NULL) {
        cout << curr->fr.numerator << "/" << curr->fr.denominator << endl;;
        curr = curr->next;
    }
}

int main() {
    fraction fr;
    int n;
    Node* curr = NULL;
    Node* head = NULL;
    Node* tail = NULL;
    FILE* f;
    fopen_s(&f, "testfile.txt", "r");

    if (f) {
        while (!feof(f)) {
            fscanf_s(f, "%d", &n);
            for (int i = 0; i < n; i  ) {
                fscanf_s(f, "%d", &fr.numerator);
                fscanf_s(f, "%d", &fr.denominator);
                curr = newNode(fr);
                addNode(curr, &head, &tail);
            }
        }

        fclose(f);
        outList(head);
    }
}

CodePudding user response:

I recommend working on the foundation first, the Fraction class. If you need to write code to access the members, maybe you are violating the encapsulation rule or the tight coupling rule.

class Fraction
{
    int   m_numerator;
    int   m_denominator;
    public:  
    Fraction();  // Default constructor, creates 0/1 fraction.
    Fraction(int numerator, int denominator);
    Fraction(const Fraction& f);  // Copy constructor
    bool  Equal_Denominators(const Fraction& f);
    friend std::ostream& operator<<(std::ostream& out, const Fraction& f);
};

Fraction::Fraction()
: m_numerator(0), m_denominator(1)
{ ; }

Fraction::Fraction(int numerator, int m_denominator)
: m_numerator(numerator), m_denominator(denominator)
{
    if (m_denominator == 0)
    {
       // Throw an exception
    }
}

Fraction::Fraction(const Fraction& f)
: m_numerator(f.m_numerator), m_denominator(f.m_denominator)
{ ; }

bool  Fraction::Equal_Denominators(const Fraction& f)
{
    return m_denomenator == f.m_denomenator;
}

std::ostream& operator<<(std::ostream& out, const Fraction& f)
{
    out << "(" << f.m_numerator << "/" << "f.m_denominator" << ")";
    return out;
}

The above code snippet gives methods for compare two fractions for equal denominators, constructing fractions and printing a fraction.

When you are traversing your list you could do something like this:

if (p->fr.Equal_Denominators(fr))
{
    // Add the fractions
}

You could also add some debugging by doing this:

while (p != nullptr)
{
    std::cout << p->fr << "\n";
}

Recommended tasks for O.P.:

  1. Overload operator>> for reading fractions from std::cin or a file.
  2. Overload operator = for adding and assigning fractions.
  3. Overload operator=.

CodePudding user response:

If you build it up from the bottom and use constructors and operators it can turn into this:

#include <string>
#include <iostream>
#include <cassert>

struct Fraction {
    // construct a Fraction from whole number or n, d
    constexpr Fraction(int n, int d=1) noexcept : numerator(n), denominator(d) { }

    // add other Fraction with matching denominator
    constexpr Fraction operator  =(const Fraction &other) noexcept {
        assert(denominator == other.denominator);
        numerator  = other.numerator;
        return *this;
    }

    // denominator may not change but numerator does
    int numerator;
    const int denominator;
};

// print Fraction nicely
std::ostream & operator <<(std::ostream &out, const Fraction &fr) {
    out << "(" << fr.numerator << " / " << fr.denominator << ")";
    return out;
}

struct List {
    struct Node {
        // create Node containing fraction and attach to parent
        constexpr Node(Node **parent, const Fraction &fr_) noexcept : next{*parent}, fr(fr_) {
            *parent = this;
        }

        // printing node just prints fraction
        std::ostream & print(std::ostream &out) const {
            return out << fr;
        }

        // Nodes are always constructed as tail so initialize to nullptr
        Node *next{nullptr};
        Fraction fr;
    };

    // construct empty List
    List() { }

    // no copying List
    List(const List &) = delete;

    // no copy asignment
    List & operator =(const List &) = delete;

    // move construct List by taking over Nodes from other
    List(List && other) : head(other.head) {
        other.head = nullptr;
    }

    // move assign List by swapping Nodes with other
    List & operator =(List &&other) {
        std::swap(head, other.head);
    }

    // deconstruct List by deleting all Nodes
    ~List() noexcept {
        while(head) {
            Node *t = head;
            head = head->next;
            delete t;
        }
    }

    // print List as sum of fractions
    std::ostream & print(std::ostream &out) const {
        for (Node *node = head; node; node = node->next) {
            node->print(out);
            if (node->next) out << "   ";
        }
        return out;
    }

    // add Fraction to list: Either adds to existing Fraction or
    // adds new Node. Fractions are sorted by denominator.
    List & operator  =(const Fraction &fr) {
        Node **tail;
        for (tail = &head; *tail; tail = &((*tail)->next)) {
            int d = (*tail)->fr.denominator;
            if (d > fr.denominator) break; // denominator too large, insert Fraction before
            if (d == fr.denominator) { // denominator matched,  = Fraction
                (*tail)->fr  = fr;
                return *this;
            }
        }
        // no matching denominator, add new node
        new Node(tail, fr);
        return *this;
    }

    // add Fraction to List and move result to return value 
    List && operator  (const Fraction &other) && {
        (*this)  = other;
        return std::move(*this);
    }

    // initialize as empty list
    Node *head{nullptr};
};

// print list
std::ostream & operator <<(std::ostream &out, const List &list) {
    return list.print(out);
}

// sum of 2 fraction gives a List    
List operator  (const Fraction &lhs, const Fraction &rhs) {
    return List{}   lhs   rhs;
}

// tired of typing so much, shorten name
using F = Fraction;

int main() {
    // You can just print sums of fractions like this
    // std::cout << F{1, 5}   F{4, 7}   F{3, 5}   F{1, 2}   F{2, 2}   F{2, 5} << std::endl;

    // or read from stdin
    List list;
    int count;
    std::cin >> count;
    while(count-- > 0) {
        int n, d;
        std::cin >> n >> d;
        list  = F{n, d};
    }
    std::cout << list << std::endl;
}
  •  Tags:  
  • c
  • Related