HW: Temperature Queries (Part 1) Points Points 10 Design 75 Working Program 15 C
ID: 3918461 • Letter: H
Question
HW: Temperature Queries (Part 1)
Points
Points
10
Design
75
Working Program
15
Code Review
100
TOTAL
Submission
Design: Submit the PDF to eCampus.
Source Code: Submit the source code (LinkedList.h, LinkedList.cpp, Node.h, TemperatureData.h, TemperatureData.cpp, TemperatureDatabase.h, TemperatureDatabase.cpp, and main.cpp files) to Mimir
To compile on the VM replace the makefile with the following:
Click to download makefile.
Specifications
Part 1: You will implement a linked list to organize temperature sensor readings from a file.
Part 2: Process a file with queries to report based on the data.
Design
Algorithm for inserting new nodes into the correct location.
Algorithm for determining if one set of data (i.e. location, date) is less than another set of data.
Additional Components: Test cases
Program
You will implement a program that receives as input two files:
A temperature file (e.g., temps.dat)
This file contains historic average temperatures for several locations in Texas. The data has been obtained from the United States Historical Climate Network (USCHN). Each line of the file contains a location, a date, and the average temperature (in Celsius) for that location and date. A string, corresponding to a meteorological station id, represents a location. For example, “411048” (string not number) corresponds to Brenham, Texas. A date is specified by two integers: a year and a month. A sample line in the temperature file would be:
410120 1893 2 6.41
The temperature value -99.99 is used by the UCHN agency to represent missing information, for example:
410120 1893 1 -99.99
Valid temperatures are assumed to be in the interval -50.0 to 50.0 (remember that they use Celsius, so this is a good range). The first valid year is 1800. The latest valid year should be our current year. You can declare a constant in your program to specify the current year. (If we were programming this to be used for real, we would instead obtain the current year from the system, so that no code changes are required for future years.)
temps.dat might look like this:
411048 2015 1 9.58
411048 2015 3 14.82
411048 2016 4 20.51
411048 2016 1 10.99
411000 1973 1 0.54
411048 2016 3 18.40
411048 2016 5 -99.99
A query file (e.g., queries.dat)
Details will be given with part 2.
Requirements
You must use this skeleton code to create your program.
Your implementation has to use a linked list to store the data you read from the temperature file.
You must implement a function named “getHead()” in the class LinkedList. This function is supposed to return the pointer to the start Node of the list.
You must implement an overloaded operator< for struct Node and you must use this operator to to compare Nodes while inserting into the LinkedList. The nodes in the linked list are:
First ordered by location
Then by date (i.e. by year and then by month)
Your program should receive the names of the input files as command line arguments. The first argument will be the temperature file, the second the queries file. We’ll use the queries file next week.
If the input files contain a line with an invalid format, you should output on the console an error message and finish executing the program.
Do not throw an exception.
Output the message in the console beginning “Error: “ followed by the description shown below followed by the invalid value. For example:
Error: Invalid temperature -1221.11
Error: Invalid year 2020
Error: Invalid month 0
Error: Unable to open input.dat
Error: Other invalid input
Examples of lines with invalid format for temps.dat:
4111000 1889 0 -4.3
4111000 1889 18 -4.3
4111000 2016 01 -1222.11
4111000 1889 .8 8.3
4111000 2015 11
You are required to use classes and comply with the “Rule of 3” (see zyBook and slides). More specifically, you need to implement the constructor, destructor, copy assignment, and copy constructor for the LinkedList class and any other class that uses the heap/freestore, but I don’t think any other class should use the heap.
The constructor for your Node and TemperatureData classes should take all data items (station id, year, month, average temperature value) as parameters. Use initialization in the “membername(value)” format (see zyBook and slides)
We’ll test these directly.
Implement the print() function for the linked list. Use this function and/or the overloaded output operator to test your results. We’ll test the linked list functions directly for part 1. The expectation is that the list will be printed out in the correct order based on the comparison rules listed earlier.
Grading
We will unit test the LinkedList class, including insert, print, constructors and rule of 3, and overloaded output operator (which is already done for you if you get print to work.
We will unit test Node and TemperatureData classes.
We will unit test TemperatureDatabase loadData() function. We will look for error messages.
Sample Input/Output Files
Building the list input files
Zip file
temp-3lines.dat, temp-7lines.dat, etc.
Hints & Comments
Write a myTest() function for the TemperatureDatabase. You can call that function from main after loading the Database to test thinks like the rule of three, print(), etc.
Use the print() function to print out your linked list so that you can make sure that you are maintaining it in order as required. First test with the small sample input files that we provide (e.g., first the one with 3 lines, then the one with 7 lines of data.), output your linked list, and inspect it to see if it is representing the input data correctly.
It is often a good idea to develop your solution incrementally, completing and testing components of your overall program as you develop them.
Points
10
Design
75
Working Program
15
Code Review
100
TOTAL
HEAD 411048820151| 9.5841104882015|3 14.82 4110488 2016 420.51 TAILExplanation / Answer
As per your question i had written a programme below.
File: node.h
#ifndef NODE
#define NODE
#include <iostream>
#include <string>
using namespace std;
struct Node
{
// Pointer to the next node in the linkedlist
int location;
int year;
int month;
double temperature;
string query;
int queryType;
Node* next;
// Default constructor
Node() : next(nullptr)
{
location = 0;
year = 0;
month = 0;
temperature = 0.0;
queryType = 0;
}
// Arguments constructor
Node(int loc, int yr, int mn, double temper) :next(nullptr)
{
location = loc;
year = yr;
month = mn;
temperature = temper;
queryType = 0;
}
// The function below is written. Do notmodify it
virtual ~Node() {}
};
#endif
File: linkedlist.h
#ifndef LINKEDLIST
#define LINKEDLIST
#include "node.h"
class LinkedList
{
private:
Node* head;
Node* tail;
public:
// Default constructor
LinkedList();
// Destructor
~LinkedList();
// Copy constructor
LinkedList(const LinkedList& other);
// Assignment constructor
LinkedList& operator=(const LinkedList&other);
// Insert a record to the linked list
void insert(int location, int year, int month,double temperature);
// Clear the content of this linkedlist
void clear();
friend std::ostream&operator<<(std::ostream&, const LinkedList&);
Node* getHead();
void insertOrder(int loc, int sYear, int eYear,int type, double value);
bool isValidateData(int loc, int sYear, inteYear);
// The functions below are written already.Do not modify them.
void print() const;
void print(std::ostream&) const;
};
std::ostream& operator<<(std::ostream& os, constLinkedList& ll);
#endif
File: linkedlist.cpp
#include "linkedlist.h"
#include <sstream>
LinkedList::LinkedList()
{
head = nullptr;
tail = nullptr;
}
LinkedList::~LinkedList()
{
clear();
}
LinkedList::LinkedList(const LinkedList& source)
{
Node* previous = source.head;
this->head = nullptr;
if (previous != nullptr)
{
Node* node = new Node;
node->location =previous->location;
node->year =previous->year;
node->month =previous->month;
node->temperature =previous->temperature;
node->query =previous->query;
node->next =previous->next;
this->head = node;
Node* current =this->head;
previous =previous->next;
while (previous !=nullptr)
{
node = newNode;
node->location = previous->location;
node->year = previous->year;
node->month = previous->month;
node->temperature = previous->temperature;
node->query = previous->query;
node->next = previous->next;
current->next = node;
current =current->next;
previous =previous->next;
}
}
}
LinkedList& LinkedList::operator=(const LinkedList&source)
{
clear();
Node* previous = source.head;
if (previous != nullptr)
{
Node* node = new Node;
node->location =previous->location;
node->year =previous->year;
node->month =previous->month;
node->temperature =previous->temperature;
node->query =previous->query;
node->next =previous->next;
this->head = node;
Node* current =this->head;
previous =previous->next;
while (previous !=nullptr)
{
node = newNode;
node->location = previous->location;
node->year = previous->year;
node->month = previous->month;
node->temperature = previous->temperature;
node->query = previous->query;
node->next = previous->next;
current->next = node;
current =current->next;
previous =previous->next;
}
}
return *this;
}
void LinkedList::insert(int location, int year, int month,double temperature)
{
Node* node = new Node(location, year, month,temperature);
Node* current = head;
Node* previous = nullptr;
if (this->head == nullptr &&this->tail == nullptr)
{
head = node;
tail = node;
return;
}
if (node->location <current->location)
{
node->next =current;
head = node;
}
while (node->location >current->location)
{
if (current->next ==nullptr)
{
current->next = node;
node->next = nullptr;
return;
}
previous = current;
current =current->next;
}
if (node->location ==current->location)
{
while (node->year >current->year)
{
if(current->next == nullptr)
{
current->next = node;
node->next = nullptr;
return;
}
previous = current;
current =current->next;
}
if (node->year ==current->year)
{
while(node->month > current->month)
{
if (current->next == nullptr)
{
current->next =node;
node->next =nullptr;
return;
}
previous = current;
current = current->next;
}
if(node->month == current->month)
{
while (node->temperature >current->temperature)
{
if (current->next ==nullptr)
{
current->next = node;
node->next = nullptr;
return;
}
previous =current;
current =current->next;
}
}
else
{
previous->next = node;
node->next = current;
}
}
else
{
previous->next = node;
node->next = current;
}
}
else
{
previous->next =node;
node->next =current;
}
}
void LinkedList::clear()
{
Node* current = this->head;
while (current != nullptr)
{
Node* previous =current;
current =current->next;
delete previous;
}
}
void LinkedList::print() const
{
print(cout);
}
void LinkedList::print(ostream& os) const
{
os << *this;
}
ostream& operator<<(ostream& os, constLinkedList& ll)
{
Node *current = ll.head;
while ( current != 0)
{
if (current->queryType !=0)
{
os<< current->location << ' ' <<current->year << ' ' << current->month << '';
if(current->queryType == 1)
os << "AVG" << ' ';
if(current->queryType == 2)
os << "MODE" << ' ';
os<< current->query << endl;
}
else
{
os<< current->location << ' ' <<current->year << ' ' << current->month << '' << current->temperature << endl;
}
current =current->next;
}
return os;
}
Node* LinkedList::getHead()
{
return this->head;
}
void LinkedList::insertOrder(int loc, int sYear, int eYear, inttype, double value)
{
Node* node = new Node(loc, sYear, eYear,value);
node->queryType = type;
if (value == -999)
{
node->query ="unknown";
}
else
{
ostringstream oss;
oss << value;
node->query =oss.str();
}
if (this->head == nullptr &&this->tail == nullptr)
{
this->head = node;
this->tail = node;
}
else
{
Node* current = head;
while (current->next !=nullptr)
{
current =current->next;
}
current->next =node;
}
}
bool LinkedList::isValidateData(int loc, int sYear, inteYear)
{
Node* current = head;
while (current->location != loc &¤t != nullptr)
{
current =current->next;
}
while (current->location == loc &¤t->year > sYear && current != nullptr)
{
current =current->next;
}
if (current->location == loc &¤t->year >= sYear && current->year <=eYear)
{
return true;
}
return false;
}
File: temperaturedb.h
#ifndef TEMPERATURE_DB
#define TEMPERATURE_DB
#include "linkedlist.h"
class TemperatureDatabase
{
public:
TemperatureDatabase() {}
~TemperatureDatabase() {}
void loadData(const std::string&data_file);
void performQuery(const std::string&query_filename);
void findMode(int location, int sYear, inteYear);
void findAVG(int location, int sYear, inteYear);
double findRoundValue(double value);
private:
LinkedList records;
LinkedList queries;
};
#endif
File: temperaturedb.cpp
#include "temperaturedb.h"
#include <fstream>
#include <vector>
void TemperatureDatabase::loadData(const std::string&data_file)
{
ifstream infile(data_file);
if (!infile.is_open())
{
cout << "Input filecould not be opened!" << endl;
return;
}
int currentYear = 2018;
int n = 0;
while (!infile.eof())
{
int location, year,month;
double value;
try
{
infile>> location >> year >> month >>value;
if(location > 99999 && location < 1000000)
{
if (year > 1799 && year <currentYear)
{
if (month > 0&& month < 13)
{
if(value > -51 && value < 51)
{
records.insert(location, year, month,value);
n++;
}
else
{
throw runtime_error("Error: Invaliddata.");
}
}
else
{
throw runtime_error("Error: Invalid month.");
}
}
else
{
throwruntime_error("Error: Invalid year.");
}
}
else
{
throw runtime_error("Error: Invalidlocation.");
}
}
catch (construntime_error& re)
{
cout<< re.what() << endl;
}
}
infile.close();
}
void TemperatureDatabase::performQuery(const std::string&query_filename)
{
ifstream infile(query_filename);
if (!infile.is_open())
{
cout << "Input filecould not be opened!" << endl;
return;
}
while (!infile.eof())
{
int location, sYear,eYear;
string query;
try
{
infile>> location >> query >> sYear >> eYear;
if(!(location > 99999 && location < 999999))
{
throw runtime_error("Error: Invalidlocation.");
}
if(!(sYear > 1799 && sYear < 2018) || !(eYear > 1799&& eYear < 2019) || (eYear < sYear))
{
throw runtime_error("Error: Invalidyear.");
}
boolvalidData = records.isValidateData(location, sYear, eYear);
if(!validData)
{
if (query == "AVG")
{
queries.insertOrder(location, sYear, eYear, 1, -999);
}
else if (query == "MODE")
{
queries.insertOrder(location, sYear, eYear, 2, -999);
}
else
{
throwruntime_error("Error: Invalid query.");
}
}
if((query == "AVG" || query == "MODE") && validData)
{
if (query == "AVG")
findAVG(location,sYear, eYear);
if (query == "MODE")
findMode(location,sYear, eYear);
}
}
catch (construntime_error& re)
{
cout<< re.what() << endl;
}
}
infile.close();
ofstream outfile("results.dat");
if (!outfile.is_open())
cout << "Output filecould not be opened!" << endl;
else
outfile <<this->queries;
}
void TemperatureDatabase::findAVG(int location, int sYear, inteYear)
{
Node* current = records.getHead();
double total = 0.0;
double average = 0.0;
int n = 0;
while (current->location < location&& current != nullptr)
{
current =current->next;
}
while (current->location == location&& current->year >= sYear && current->year<= eYear)
{
total +=current->temperature;
current =current->next;
n++;
}
if (n != 0)
{
average = total / n;
queries.insertOrder(location,sYear, eYear, 1, average);
}
}
void TemperatureDatabase::findMode(int location, int sYear, inteYear)
{
Node* current = records.getHead();
vector<int> positives(51, 0);
vector<int> negatives(50, 0);
int temp = 0;
int mode = 0;
while (current->location != location&& current != nullptr)
{
current =current->next;
}
while (current->location == location&& current->year >= sYear && current->year<= eYear)
{
double value =current->temperature;
if (value >= 0)
{
value =findRoundValue(value);
positives.at((int)value) += 1;
}
else
{
value =findRoundValue(value);
negatives.at(-1 * (int)value - 1) += 1;
}
current =current->next;
}
for (unsigned int i = 0; i <positives.size(); i++)
{
if (positives.at(i) >temp)
{
mode =i;
temp =positives.at(i);
}
}
for (unsigned int i = 0; i <negatives.size(); i++)
{
if (negatives.at(i) >temp)
{
mode = -1* i - 1;
temp =negatives.at(i);
}
}
queries.insertOrder(location, sYear, eYear,2, mode);
}
double TemperatureDatabase::findRoundValue(double value)
{
double currentVal = value;
if (value >= 0)
{
if ((currentVal -floor(value)) >= 0.5)
returnceil(value);
else
returnfloor(value);
}
else
{
if(-(currentVal)-(floor(value)) >= 0.5)
returnceil(value);
else
returnfloor(value);
}
}
// File: main.cpp
#include "temperaturedb.h"
int main(int argc, char** argv)
{
if (argc < 3)
{
cout << "Validcommandline arguments are not found." << endl;
return 1;
}
TemperatureDatabase db;
db.loadData(argv[1]);
db.performQuery(argv[2]);
return 0;
}
Please Hit Like if you find this answer helpful.
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.