Rodex_ icon

Hashtable_Algorithm

Rodex_ | PRO | 04/03/17 04:19:00 PM UTC | 0 ⭐ | 278 👁️ | Never ⏰ | []
C++ |

24.97 KB

|

None

|

0 👍

/

0 👎

=================================================== STOCK.H ========================================================
 
#ifndef HASHTABLE_STOCK_H
#define HASHTABLE_STOCK_H
 
#include <iostream>
#include <vector>
 
/**
 * Represents price data of a stock for a single day
 */
class PriceData {
    std::string date;
    double open, high, low, close, adj_close;
    int volume;
public:
    /**
     * Creates price data for a single day
     * @param date Date of given price data
     * @param open Open value of given day
     * @param high High value of given day
     * @param low Low value of given day
     * @param close Close value of given day
     * @param volume Volume of given day
     * @param adj_close Adjusted close value of given day
     */
    PriceData(std::string date, double open, double high, double low, double close, int volume, double adj_close);
    /**
     * Returns the date of this PriceData
     * @return a string containing the date
     */
    std::string getDate();
    /**
     * Returns the open value of this PriceData
     * @return a double containing the open value
     */
    double getOpen();
    /**
     * Returns the high value of this PriceData
     * @return a double containing the high value
     */
    double getHigh();
    /**
     * Returns the low value of this PriceData
     * @return a double containing the low value
     */
    double getLow();
    /**
     * Returns the close value of this PriceData
     * @return a double containing the close value
     */
    double getClose();
    /**
     * Returns the volume value of this PriceData
     * @return an int containing the volume value
     */
    int getVolume();
    /**
     * Returns the adjusted close value of this PriceData
     * @return a double containing the adjusted close value
     */
    double getAdjClose();
 
};
 
/**
 * Represents a stock with a name, member code, security identification number and price data of last 30 days
 */
class Stock {
    std::string name;
    std::string member_code;
    // Security Identification Number
    int sin;
    PriceData* price_data[30];
public:
    /**
     * Creates an empty stock
     */
     Stock();
    /**
     * Creates a new stock
     * @param name Stock name
     * @param member_code Short name of stock
     * @param sin Security Identification Number
     */
    Stock(std::string name, std::string member_code, int sin);
    /**
     * Import price data of last 30 days from a csv file
     * @param filepath path to csv file (including filename + ending)
     */
    void import_price_data(std::string filepath);
    /**
     * Returns the name of the stock
     * @return a string containing the name
     */
    std::string getName();
    /**
     * Returns the member code of the stock
     * @return a string containing the member code
     */
    std::string getMemberCode();
    /**
     * Returns the security identification number of the stock
     * @return an int containing the sin
     */
    int getSIN();
    /**
     * Returns the PriceData Array of the stock
     * @return an array of PriceData Pointer of length 30
     */
    PriceData** getPriceData();
    /**
     * Sets the PriceData Array
     * @param data an array of PriceData Pointer of length 30
     */
    void setPriceData(PriceData** data);
};
 
#endif //HASHTABLE_STOCK_H
 
 
=================================================== STOCK.CPP ======================================================
 
#include "stock.h"
#include <fstream>
#include <sstream>
#include <cstring>
 
PriceData::PriceData(std::string date, double open, double high, double low, double close, int volume, double adj_close)
        : date(date), open(open), high(high), low(low), close(close), volume(volume), adj_close(adj_close) {
}
 
std::string PriceData::getDate() {
    return date;
}
 
double PriceData::getOpen() {
    return open;
}
 
double PriceData::getHigh() {
    return high;
}
 
double PriceData::getLow() {
    return low;
}
 
double PriceData::getClose() {
    return close;
}
 
int PriceData::getVolume() {
    return volume;
}
 
double PriceData::getAdjClose() {
    return adj_close;
}
 
 
Stock::Stock(std::string name, std::string member_code, int sin) : name(name), member_code(member_code), sin(sin) {
    for (int i = 0; i < 30; i++) {
        price_data[i] = nullptr;
    }
}
 
Stock::Stock() {
    name = nullptr;
    member_code = nullptr;
    sin = -1;
}
 
void Stock::import_price_data(std::string filepath) {
    std::ifstream file(filepath, std::ios::in);
    std::string line;
    int line_numbers = 0;
    for (; std::getline(file, line); line_numbers++);
 
    std::string date, open, high, low, close, volume, adj_close;
    double open_d, high_d, low_d, close_d, adj_close_d;
    int volume_d;
    std::ifstream datei;
    //open file with correct Filepath of Input
    datei.open(filepath, std::ios::in);
    //read first line without values to get to second line
    getline(datei, date, '\n');
    for (int i = 0; i < 30 && i < line_numbers-1; ++i) {
        //read the line of the file and get the values into the correct variables
        getline(datei, date, ',');
        getline(datei, open, ',');
        getline(datei, high, ',');
        getline(datei, low, ',');
        getline(datei, close, ',');
        getline(datei, volume, ',');
        getline(datei, adj_close, '\n');
        //prepare stringstreams to get the values from string into double
        std::stringstream open_s(open);
        std::stringstream high_s(high);
        std::stringstream low_s(low);
        std::stringstream close_s(close);
        std::stringstream volume_s(volume);
        std::stringstream adj_close_s(adj_close);
        //convert stringstreams in doubles
        open_s >> open_d;
        high_s >> high_d;
        low_s >> low_d;
        close_s >> close_d;
        adj_close_s >> adj_close_d;
        volume_s >> volume_d;
        if(!open_s.fail() && !high_s.fail() && !low_s.fail() && !close_s.fail() && !adj_close_s.fail() && !volume_s.fail()) { //erstelle neues Objekt und übergebe die daten
            if(price_data[i] != nullptr) {
                delete price_data[i];
            }
            price_data[i] = new PriceData(date, open_d, high_d, low_d, close_d, volume_d, adj_close_d);
        }
    }
}
 
std::string Stock::getName() {
    return name;
}
 
std::string Stock::getMemberCode() {
    return member_code;
}
 
int Stock::getSIN() {
    return sin;
}
 
PriceData** Stock::getPriceData() {
    return price_data;
}
 
void Stock::setPriceData(PriceData **data) {
    for(int i = 0; i < 30; i++){
        price_data[i] = data[i];
    }
}
 
=================================================== HASHTABLE.H ====================================================
 
#ifndef HASHTABLE_HASHTABLE_H
#define HASHTABLE_HASHTABLE_H
 
#include "stock.h"
 
/**
 * Represents a HashTable for saving stock information
 */
class HashTable {
    const static int array_size = 1999;
    // Data format to store stocks in
    Stock* stocks[array_size];
 
public:
    const static int HASH_BY_NAME = 0;
    const static int HASH_BY_CODE = 1;
    /**
     * Creates a new HashTable
     */
    HashTable();
    /**
     * Hash function, which creates an integer value from a string
     * @param str string to be hashed
     * @return an integer value representing a hashed value of the given string
     */
    int hash(std::string str);
    /**
     * Puts a stock into the HashTable
     * @param stock Stock to be inserted
     * @param hash_by HASH_BY_NAME or HASH_BY_CODE
     */
    void add(Stock* stock, int hash_by);
    /**
     * Removes a stock from the HashTable
     * @param name Name of stock to be removed
     * @param hash_by HASH_BY_NAME or HASH_BY_CODE
     */
    void remove(std::string name, int hash_by);
    /**
     * Searches a stock in the HashTable and returns it if found
     * @param name Name of wanted stock
     * @param hash_by HASH_BY_NAME or HASH_BY_CODE
     * @return Wanted stock, if found. Else it will return null
     */
    Stock* search(std::string name, int hash_by);
    /**
     * Saves the complete HashTable into a file
     * @param filepath the path (+filename) where it should be saved
     */
    void saveToFile(std::string filepath);
    /**
     * Reads a complete HashTable from a file
     * @param filepath the path (+filename) from where it should be read
     */
    void readFromFile(std::string filepath);
 
};
 
#endif //HASHTABLE_HASHTABLE_H
 
 
 
=================================================== HASHTABLE.CPP ==================================================
 
#include <string.h>
#include <math.h>
#include <fstream>
#include <sstream>
#include "hashtable.h"
 
HashTable::HashTable() {
    for(int i = 0; i < array_size; i++){
        stocks[i] = nullptr;
    }
}
 
int HashTable::hash(std::string str) {
    int intLength = str.length() / 4;
    long sum = 0;
    for (int j = 0; j < intLength; j++) {
        char c[5];
        std::string tmp = str.substr(j * 4, (j * 4) + 4);
        strcpy(c, tmp.c_str());
        long mult = 1;
        for (int k = 0; k < 5; k++) {
            sum += c[k] * mult;
            mult *= 256;
        }
    }
 
    int lengthMax = str.length() % 4;
    char c[lengthMax];
    std::string tmp = str.substr(intLength * 4);
    strcpy(c, tmp.c_str());
    long mult = 1;
    for (int k = 0; k < lengthMax; k++) {
        sum += c[k] * mult;
        mult *= 256;
    }
 
    return(sum % array_size);
}
 
void HashTable::add(Stock* stock, int hash_by) {
    int hashed = 0;
    if(hash_by == HASH_BY_NAME) {
        hashed = hash(stock->getName());
    }else{
        hashed = hash(stock->getMemberCode());
    }
    //look in the list if the hashed position for stock is empty
    if(stocks[hashed] == nullptr){
        stocks[hashed] = stock;
    }else{
        //if not empty start the search algorithm for empty position
        int plus = 1;
        int next_pos = 0;
        for(int i = 1; i <= array_size;){
            int x = (int)pow(i,2);
            //function to take the numbers of square always negative and positive
            if(!plus){
                x = (-1) * x;
                i++;
            }
            plus = (plus+1)%2;
            //calculation to get the correct value always as a positive integer
            next_pos = ((hashed+x)% array_size + array_size) % array_size ;
            if(stocks[next_pos] == nullptr){
                stocks[next_pos] = stock;
                break;
            }
        }
    }
}
 
void HashTable::remove(std::string name, int hash_by) {
    int hashed = hash(name);
    //look in the list if correct stock from the input is on the hashed position
    if((hash_by == HASH_BY_NAME && stocks[hashed] != nullptr && stocks[hashed]->getName() == name) ||
            (hash_by == HASH_BY_CODE && stocks[hashed] != nullptr && stocks[hashed]->getMemberCode() == name)){
        delete stocks[hashed];
        stocks[hashed] = nullptr;
    }else{
        int plus = 1;
        int next_pos = 0;
        for(int i = 1; i <= array_size;){
            int x = (int)pow(i,2);
            //function to take the numbers of square always negative and positive
            if(!plus){
                x = (-1) * x;
                i++;
            }
            plus = (plus+1)%2;
            //calculation to get the correct value always as a positive integer
            next_pos = ((hashed+x) % array_size + array_size) % array_size ;
            if((hash_by == HASH_BY_NAME && stocks[next_pos] != nullptr && stocks[next_pos]->getName() == name) ||
                    (hash_by == HASH_BY_CODE && stocks[next_pos] != nullptr && stocks[next_pos]->getMemberCode() == name)){
                delete stocks[next_pos];
                stocks[next_pos] = nullptr;
                break;
            }
        }
    }
}
 
Stock* HashTable::search(std::string name, int hash_by) {
    int hashed = hash(name);
    //look in the list if correct stock from the input is on the hashed position
    if((hash_by == HASH_BY_NAME && stocks[hashed] != nullptr && stocks[hashed]->getName() == name) ||
       (hash_by == HASH_BY_CODE && stocks[hashed] != nullptr && stocks[hashed]->getMemberCode() == name)){
        return stocks[hashed];
    }else{
        //if not on the hashed position start with the search algorithm
        int plus = 1;
        int next_pos = 0;
        for(int i = 1; i <= array_size;){
            int x = (int)pow(i,2);
            //function to take the numbers of square always negative and positive
            if(!plus){
                x = (-1) * x;
                i++;
            }
            plus = (plus+1)%2;
            //calculation to get the correct value always as a positive integer
            next_pos = ((hashed+x) % array_size + array_size) % array_size ;
            if(hash_by == HASH_BY_NAME && stocks[next_pos] != nullptr && stocks[next_pos]->getName() == name ||
               hash_by == HASH_BY_CODE && stocks[next_pos] != nullptr && stocks[next_pos]->getMemberCode() == name){
                return stocks[next_pos];
            }
        }
    }
    return nullptr;
}
 
void HashTable::saveToFile(std::string filepath) {
    int count_pricedata;
    std::ofstream file;
    file.open(filepath, std::ios::out);
 
    for(int i = 0; i < array_size; i++){
        if(stocks[i] != nullptr){
            // Write stock information
            file << i << " " << stocks[i]->getName() << " " << stocks[i]->getMemberCode() << " " << stocks[i]->getSIN();
            count_pricedata = 0;
            for(int j = 0; j < 30; j++){
                if(stocks[i]->getPriceData()[j] != nullptr){
                    count_pricedata++;
                }
            }
            file << " " << count_pricedata << "\n";
            // Write price data
            for(int j = 0; j < 30; j++){
                if(stocks[i]->getPriceData()[j] != nullptr){
                    file << j << " " << stocks[i]->getPriceData()[j]->getDate();
                    file << " " << stocks[i]->getPriceData()[j]->getOpen();
                    file << " " << stocks[i]->getPriceData()[j]->getHigh();
                    file << " " << stocks[i]->getPriceData()[j]->getLow();
                    file << " " << stocks[i]->getPriceData()[j]->getClose();
                    file << " " << stocks[i]->getPriceData()[j]->getVolume();
                    file << " " << stocks[i]->getPriceData()[j]->getAdjClose() << "\n";
                }
            }
        }
    }
 
    // End of File
    file << "eof" << " \n";
 
    file.close();
}
 
void HashTable::readFromFile(std::string filepath) {
    std::string in, name, membercode, sin_s, date;
    int count_pricedata, sin, index, volume, pdindex;
    double open, high, low, close, adjclose;
    std::ifstream file;
    file.open(filepath, std::ios::in);
 
    for(int i = 0; i < array_size; i++){
        getline(file, in, ' ');
        // If not end of file
        if(in != "eof"){
            // Read stock information
            getline(file, name, ' ');
            getline(file, membercode, ' ');
            getline(file, sin_s, ' ');
            std::stringstream sin_stream(sin_s);
            sin_stream >> sin;
            std::stringstream index_stream(in);
            index_stream >> index;
            // Insert stock into hashtable
            Stock* stock = new Stock(name, membercode, sin);
            stocks[index] = stock;
 
            // Read price data
            getline(file, in, '\n');
            std::stringstream pricedata_stream(in);
            pricedata_stream >> count_pricedata;
 
            PriceData* data[30];
            for(int j = 0; j < 30; j++){
                data[j] = nullptr;
            }
            for(int j = 0; j < count_pricedata; j++){
                getline(file, in, ' ');
                {
                    std::stringstream in_stream(in);
                    in_stream >> pdindex;
                    getline(file, date, ' ');
                }
                getline(file, in, ' ');
                {
                    std::stringstream in_stream(in);
                    in_stream >> open;
                }
                getline(file, in, ' ');
                {
                    std::stringstream in_stream(in);
                    in_stream >> high;
                }
                getline(file, in, ' ');
                {
                    std::stringstream in_stream(in);
                    in_stream >> low;
                }
                getline(file, in, ' ');
                {
                    std::stringstream in_stream(in);
                    in_stream >> close;
                }
                getline(file, in, ' ');
                {
                    std::stringstream in_stream(in);
                    in_stream >> volume;
                }
                getline(file, in, '\n');
                {
                    std::stringstream in_stream(in);
                    in_stream >> adjclose;
                }
 
                PriceData* priceData = new PriceData(date, open, high, low, close, volume, adjclose);
                data[pdindex] = priceData;
            }
            stocks[index]->setPriceData(data);
        }else{
            break;
        }
    }
 
    file.close();
}
 
 
 
=================================================== MAIN.CPP ========================================================
 
#include <iostream>
#include <sstream>
#include <array>
#include <iomanip>
#include "hashtable.h"
 
 
Stock* searchStock(std::string name, HashTable* table_names, HashTable* table_codes){
    Stock *s = nullptr;
    if(name.length() > 4) {
        s = table_names->search(name, HashTable::HASH_BY_NAME);
    }else{
        s = table_codes->search(name, HashTable::HASH_BY_CODE);
    }
    if(s == nullptr){
        if(name.length() > 4) {
            s = table_codes->search(name, HashTable::HASH_BY_CODE);
        }else{
            s = table_names->search(name, HashTable::HASH_BY_NAME);
        }
    }
    return s;
}
 
void printMenuInfo(){
    std::cout << "\n\n";
    std::cout << "==============================" << std::endl;
    std::cout << "1 ... Add stock" << std::endl;
    std::cout << "2 ... Search stock" << std::endl;
    std::cout << "3 ... Delete stock" << std::endl;
    std::cout << "4 ... Import price data from file" << std::endl;
    std::cout << "5 ... Plot price data of a stock" << std::endl;
    std::cout << "6 ... Save hashtable to file" << std::endl;
    std::cout << "7 ... Load hashtable from file" << std::endl;
    std::cout << "8 ... Quit program" << std::endl;
    std::cout << "------------------------------" << std::endl;
}
 
int main() {
 
    std::string in = "";
    HashTable *table_names = new HashTable();
    HashTable *table_codes = new HashTable();
 
    // QUIT if input is 8
    while(in.compare("8") != 0){
        printMenuInfo();
        std::cin >> in;
        if(in.compare("1") == 0){
            // ADD
            std::string name, member_code, sin_s;
            int sin;
            std::cout << "Name: ";
            std::cin >> name;
            std::cout << "Member Code: ";
            std::cin >> member_code;
            int fail = 0;
            do {
                std::cout << "Security Identification Number: ";
                std::cin >> sin_s;
                std::stringstream s(sin_s);
                s >> sin;
                if(s.fail()){
                    fail = 1;
                }else{
                    fail = 0;
                }
            }while(fail);
            Stock *stock = new Stock(name, member_code, sin);
            table_names->add(stock, HashTable::HASH_BY_NAME);
            table_codes->add(stock, HashTable::HASH_BY_CODE);
        }else if(in.compare("3") == 0){
            // DELETE
            std::string name;
            std::cout << "Name/Member Code: ";
            std::cin >> name;
            Stock *s = searchStock(name, table_names, table_codes);
            if(s != nullptr) {
                table_names->remove(s->getName(), HashTable::HASH_BY_NAME);
                table_codes->remove(s->getMemberCode(), HashTable::HASH_BY_CODE);
                std::cout << name << " successfully removed!" << std::endl;
            }else{
                std::cout << "Could not delete stock! (Not found)";
            }
        }else if(in.compare("4") == 0){
            // IMPORT
            std::string name;
            std::cout << "Name/Member Code: ";
            std::cin >> name;
            Stock* s = searchStock(name, table_names, table_codes);
            if(s != nullptr) {
                std::string filepath;
                std::cout << "Filepath: ";
                std::cin >> filepath;
                s->import_price_data(filepath);
                std::cout << "Import successful!" << std::endl;
            }else{
                std::cout << "Could not find stock!"  << std::endl;
            }
 
        }else if(in.compare("2") == 0){
            // SEARCH
            std::string name;
            std::cout << "Name/Member Code: ";
            std::cin >> name;
            Stock* s = searchStock(name, table_names, table_codes);
            if(s != nullptr) {
                std::cout << "NAME: " << s->getName() << std::endl;
                std::cout << "MEMBER CODE: " << s->getMemberCode() << std::endl;
                std::cout << "SIN: " << s->getSIN() << std::endl;
                PriceData* data = s->getPriceData()[0];
                if(data != nullptr) {
                    std::cout << "High: " << data->getHigh() << std::endl;
                }else{
                    std::cout << "No price data found" << std::endl;
                }
            }else{
                std::cout << "Could not find stock!";
            }
        }else if(in.compare("5") == 0){
            // PLOT
            std::string name;
            std::cout << "Name/Member Code: ";
            std::cin >> name;
            Stock* s = searchStock(name, table_names, table_codes);
            //check if the stock from input is available
            if(s != nullptr) {
                //define the size of the Plotting window
                constexpr size_t entries = 30;
                constexpr size_t steps   = 25;
                //the array/vector to put the values of the stock in it
                std::array<int, entries> arr;
                double max = 0;
                PriceData* data = nullptr;
                //get the max value of the chosen stock
                for (int i = 0; i < entries; ++i) {
                    data = s->getPriceData()[i];
                    if (data != nullptr)
                        max = std::max(max, data->getHigh());
                }
                //write every value of the last 30 days in the correct position of the array/vector
                auto adjust = max / steps;
                for (int i = 0; i < entries; ++i) {
                    data = s->getPriceData()[i];
                    arr[i] = (data != nullptr) ? data->getHigh() / adjust : 0;
                }
                // plot the graph of the stock
                std::cout << "\n" << std::endl; // clear new line...
                for (int j = steps; j > 0; j--) {
                    for (int i = 0; i < entries; ++i)
                        if (arr[i] >= j)
                            std::cout << "#";
                        else
                            std::cout << " ";
                    std::cout << " " << j*adjust << std::endl;
                }
 
                //function to add the correct numbers of day in under my plotted graph
                auto plot_numbers = [&](const std::vector<int>& in) {
                    for (auto& i : in) std::cout << i;
                    std::cout << std::endl;
                };
                plot_numbers(std::vector <int>{0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3});
                plot_numbers(std::vector <int>{1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0});
 
 
 
            }else{
                std::cout << "Could not find stock!";
            }
        }else if(in.compare("6") == 0){
            // SAVE
            std::cout << "Saving to file..." << std::endl;
            table_names->saveToFile("hashtable_names.txt");
            table_codes->saveToFile("hashtable_codes.txt");
            std::cout << "Saved!" << std::endl;
        }else if(in.compare("7") == 0){
            // LOAD
            std::cout << "Reading from file..." << std::endl;
            table_names->readFromFile("hashtable_names.txt");
            table_codes->readFromFile("hashtable_codes.txt");
            std::cout << "Finished!" << std::endl;
        }
    }
 
    std::cout << "Exiting program..." << std::endl;
    std::cout << "Good Bye!" << std::endl;
 
    return 0;
}

Comments