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.:
- Overload
operator>>
for reading fractions fromstd::cin
or a file. - Overload
operator =
for adding and assigning fractions. - 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;
}