Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Make sure there are the three separated into multiple files, including a HashTab

ID: 3832985 • Letter: M

Question

Make sure there are the three separated into multiple files, including a HashTable.h, HashTable.cpp, and FinalProject.cpp.

HashTable.h is the h file that outlines everything, HashTable.cpp creates it and FinalProject.cpp opens the command line argument, takes user input, uses the defined functions and displays results.

You need to build a hash table using two different algorithms for collision resolution – open addressing and chaining. Your hash table should be build from the provided data set called playerData. You also need to evaluate the performance of each algorithm in terms of how many collisions are generated while the table is built and the operations required to retrieve data from the table.

Assignment data

There is a file called playerData that includes every Major League Baseball player on every team since 1985. For example, the first two rows in the file show the header row, which shows what each column includes, and the first row of data. The first row of data is:

1985, ATL, NL, barkele01, 870000, Len, Barker, 1955, USA, 225, 77, R, R

The fields in the header row show:
yearID
– year, between 1985 and 2016
teamID – three-letter abbreviation for team
leagueID – league that the team belongs to, either National League (NL) or American League (AL)
playerID – ID for the player, used in the Lahman database where I downloaded data salary – how much money the player made that year
firstName – player’s first name
lastName – player’s last name
birthYear – year the player was born
birthCountry – country where the player was born
weight – player’s weight
height – player’s height
bats – how the player bats, either right (R ) or left (L) handed, or switch (S).
throws – how the player throws, either right (R ) or left (L) handed.

Assignment requirements

Build hash table

You need to process the data provided and build a hash table, where the key for entries in the hash table is the player’s first and last name, concatenated. For example, for the first row in the file, the key would be LenBarker.

For a hash function, you can use the hashSum function discussed in lecture, or any other hash function that you want to try. In your project report, describe the hash function that you use.

Each player should only appear in the hash table one time. Each record in the hash table needs to include the player’s information, including first and last name, birth year and country, height and weight, and batting and throwing. Each record also needs to include a list of all the teams and years that the player was active, and their salary for that year. For example, the hash table entry for Len Barker would be:

First name: Len
Last name: Barker Year born: 1955 Country born: USA Weight: 225
Height: 77
Bats: R
Throws: R
Teams and salary: 1985, ATL, NL, 870000 1986, ATL, NL, 880000 1987, ATL, NL, 890000 1987, ML4, AL, 72500 1988, ATL, NL, 900000

The teams and salary entries are taken from the playerData file for every row where the player’s name appears. Note: you could have multiple players with the same name. You will need some method for verifying the uniqueness of a player. For example, if there were another Len Barker in the data file, you might want to check the height and weight or year born information to determine if it’s the same person.

Set hash table size using command line argument

Use a command line argument to set the size of the hash table. There are 5072 unique players in the playerData file. Run your program multiple times, using 5072 as the minimum hash table size, and increase the size of the hash table up to 15K- 20K. In your project write up, describe the effect that increasing the hash table size had on the number of collisions for both algorithms.

The file data I have uploaded is not this large, but this is the format it will be in. The info must be read in and opened from a comand line argument of playerData.txt The program you write should also be able to handle collisions such as the same player with different years. The file section I have copied may not have collisions, but change some of the data to test that your collision checking works.

Collision analysis

As part of this assignment, you need to evaluate the performance of two collision resolution algorithms – open addressing and chaining. My suggestion for approaching this problem is to build two hash tables as you are reading the data from the file – one hash table resolves collisions using open addressing and the other hash table resolves collisions using chaining.

Collisions during building the table

As you are building the hash table, you need to count the number of collisions that each collision resolution algorithm generates. You also need to count the number of search operations needed to find a location for the record. For example, if you are using chaining and there is a collision and you traverse three records in a linked list to find an open location, then the number of search operations is 3. If you get a collision using open addressing and evaluate 4 entries in the hash table before finding an open location, then the number of search operations is 4.

Once the table is built, display the following information clearly for the user:

Hash table size: <table size>
Collisions using open addressing: <collisions> Collisions using chaining: <chaining collisions>
Search operations using open addressing: <search ops> Search operations using chaining: <search ops chaining>

User input

Your program needs to present the user with the option of looking up a player in the hash table. A suggested menu is as follows:

Query hash table

Quit program

If the user selects Query hash table, they should be asked to input the name of a player. If the player is in the hash table, display the record for that player, including all of the information shown on the previous page for the Len Barker example. If the player is not in the hash table, display “Player not found”, and display the menu again so the user can select another player or quit the program.

Linear searches needed to retrieve data

In addition to displaying player information, your program should also display the number of search operations needed to find the player in the hash table for both open addressing and chaining.

For example, if the hash code for a player is 0, and no other players are stored at that index, then there would be zero searches needed to find the players information. However, if there are 5 players with the same hash code, and the player you need was stored at the end of the linked list for that index using chaining, then the number of searches is 5.

Display the following information, in addition to the player information: Search operations using open addressing: <search ops>

Search operations using chaining: <search ops chaining>

Hints

Your code needs to be separated into multiple files, including a HashTable.h, HashTable.cpp, and FinalProject.cpp.

If you use an array for your hash table, you will need to use dynamic memory to create the array. For the chaining algorithm, you store a dynamically created array of pointers. For the open addressing algorithm, you need a regular dynamic array.

Each player should only be stored in the hash table one time. The list of teams for that player needs to be an item in the player’s record.

Explanation / Answer

main.cpp

#include <string>
#include <chrono>
#include <memory>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <iostream>

#include "HashTable.hpp"
#include "PlayerInfo.hpp"

using namespace std;

void die(string message) {
    cout << message << endl;
    exit(0);
}

void PopulateHashTable(string filename, std::shared_ptr<HashTable> map) {
    ifstream file(filename);
  
    // non-existant or corrupted file
    if(file.fail()) {
        die("Could not open file");
    }
  
    string line;
  
    string ignoreHeader;
    std::getline(file, ignoreHeader);
  
    // cout << ignoreHeader << endl;
    // std::setiosflags(ios::fixed);
  
    while(std::getline(file, line)) {
        auto playerInfo = PlayerInfo::ConstructFrom(line);
      
        // add playerInfo to the hash table.
        auto key = PlayerInfo::MakeKey(playerInfo);
        map->put(key, playerInfo);
    }
}

int getTableSize(string size) {
    char multiplier = ' ';
    float number;
  
    istringstream ss(size);
    ss >> number >> multiplier;
  
    switch (multiplier) {
        case 'k':
        case 'K':
            // Kilo
            number *= 1000;
            break;
          
        case ' ':
            break;
          
        default:
            cout << "Only K/k multiplier is supported!" << endl;
            break;
    }

    return number;
}

int main(int argc, const char * argv[]) {

    string dmenu = "1. Query hash table "
                    "2. Quit program ";
  
    string help = "usage: $executable [input file] [hashtable size] "
                  "example: $exe PlayerData.txt 5072";
  
    if (argc < 3) {
        cout << "Missing arguments to the program!" << endl;
        die(help);
    }
  
    int choice = 0;
    bool done = false;
  
    string filename {argv[1]};
    int hashSize = getTableSize(argv[2]);
  
    // create collision counter variables
    std::shared_ptr<CollisionCounter> linearProbeStats(new CollisionCounter("(linear probe)"));
    std::shared_ptr<CollisionCounter> chainingStats(new CollisionCounter("(chaining)"));
  
    // Let c++11 smart pointers do memory management for me.
    auto map = std::shared_ptr<HashTable>(
                    new HashTable(hashSize,
                                  std::unique_ptr<ChainingResolver>(new ChainingResolver(chainingStats)))
                );
    auto map2 = std::shared_ptr<HashTable>(
                    new HashTable(hashSize,
                                  std::unique_ptr<CollisionResolver>(new LinearProbingResolver(linearProbeStats)))
                );
  
    PopulateHashTable(filename, map);
    PopulateHashTable(filename, map2);
  
    cout << "Hash table size: " << hashSize << endl;
    cout << "Collisions using open addressing: " << linearProbeStats->addCollisions << endl;
    cout << "Collisions using chaining: " << chainingStats->addCollisions << endl;
    cout << "Search operations using chaining: " << chainingStats->lookupCollisions << endl;
    cout << "Search operations using open addressing: " << linearProbeStats->lookupCollisions << endl;
  
    linearProbeStats->resetCounters();
    chainingStats->resetCounters();
  
    do {
        cout << dmenu;
        cin >> choice;
      
        // flush the newlines and other characters
        cin.clear();
        cin.ignore();
      
        switch (choice) {
            case 1:
            {
                string firstName, lastName;
              
                cout << "Enter first name: " << endl;
                std::getline(cin, firstName);
                cout << "Enter last name: " << endl;
                std::getline(cin, lastName);
              
                auto key = PlayerInfo::MakeKey(firstName, lastName);
              
                // look up with chaining
                {
                    auto found = map->get(key);

                    cout << endl << "Search operations using chaining: " << chainingStats->lookupCollisions << endl;
                    found->show();
                    chainingStats->resetCounters();
                }
              
                // look up with linear probing
                {
                    auto found = map2->get(key);
                  
                    cout << "Search operations using open addressing: " << linearProbeStats->lookupCollisions << endl;
                    found->show();
                    linearProbeStats->resetCounters();
                }
              
                break;
            }
              
            case 2:
            {
                done = true;
                break;
            }
          
            default:
            {
                // ignore unrecognized input.
                // and let program continue.
            }
        }
      
    } while(!done);
  
    cout << "Goodbye!" << endl;
    return 0;
}

HashTable.cpp

#include "HashTable.hpp"

extern uint32_t SuperFastHash (const char * data, int len);

HashTable::HashTable(int capacity, std::unique_ptr<CollisionResolver> resolverStrategy)
    : capacity(capacity), size(0) {
    // construct zero initialized hash table of size
    table = new HashEntry *[capacity];
    this->resolverStrategy = std::move(resolverStrategy);
}

HashTable::~HashTable() {
    cout << "Deleted hash table" << endl;
    clear();
    delete table;
}

unsigned int HashTable::hashfunc(const char* str, unsigned int seed) {
    // Based on work of Paul Larson & George V Reilly from Microsoft.
    // Simple and yet fast so that we get O(1) for hash function look ups.
  
    // For more rigorous hash function. call superFastHash from hashing.cpp
    // return SuperFastHash(str, static_cast<int>(strlen(str)));
    unsigned int hash = seed;
    while (*str) hash = hash * 101 + *str++;
    return hash;
}

void HashTable::put(string key, PlayerInfo value) {
    auto index = getIndex(key);
  
    auto collision = table[index];
  
    if (!collision) table[index] = new HashEntry(value);
    else resolverStrategy->add(this, new HashEntry(value), index);
  
    size++;
}

std::unique_ptr<PlayerInfo> HashTable::get(string key) {
    auto index = getIndex(key);
  
    auto found = table[index];
    if (!found) return std::unique_ptr<PlayerInfo>(new NullPlayerInfo());
  
    return resolverStrategy->get(this, key, index);
}

void HashTable::clear() {
    if (!table) {
        return;
    }
  
    auto tsize = capacity;
    while (tsize-- > 0) {
        auto entry = table[tsize];
        if (!entry) continue;
      
        // Delete the record. Call resolver because we
        // don't know the internal of how collision is resolved.
        resolverStrategy->Delete(entry);
    }
}

void HashTable::rehash() {
    throw runtime_error("Not implemented!");
}

inline int HashTable::getIndex(string key) {
    auto hash = hashfunc(key.c_str());
    // Ensure we are not out of bounds of the hash table size
    return hash % capacity;
}

HashTable.hpp

#ifndef HashTable_hpp
#define HashTable_hpp

#include <memory>
#include <iostream>

#include "PlayerInfo.hpp"
#include "CollisionResolver.hpp"

using namespace std;

class HashEntry {
public:
    PlayerInfo player;
  
    HashEntry(PlayerInfo value)
        : player(value), next(nullptr)
    { };
  
    HashEntry* next;
};

class HashTable {
private:
    HashEntry **table;
    std::unique_ptr<CollisionResolver> resolverStrategy;
    int capacity;
    int size;
  
    unsigned int hashfunc(const char* str, unsigned int seed = 1);
    inline int getIndex(string key);
  
    // Resolvers are friend classes
    friend class LinearProbingResolver;
    friend class ChainingResolver;
  
public:
    HashTable(int capacity = 1024, std::unique_ptr<CollisionResolver> resolverStrategy = nullptr);
    ~HashTable();
  
    void put(string key, PlayerInfo value);
    std::unique_ptr<PlayerInfo> get(string key);
    void clear();
    void rehash();
};

#endif /* HashTable_hpp */

Hashing.cpp

#include <stdint.h>
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)
    || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16_t *) (d)))
#endif

#if !defined (get16bits)
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)
        +(uint32_t)(((const uint8_t *)(d))[0]) )
#endif

uint32_t SuperFastHash (const char * data, int len) {
    uint32_t hash = len, tmp;
    int rem;
  
    if (len <= 0 || data == nullptr) return 0;
  
    rem = len & 3;
    len >>= 2;
  
    /* Main loop */
    for (;len > 0; len--) {
        hash += get16bits (data);
        tmp    = (get16bits (data+2) << 11) ^ hash;
        hash   = (hash << 16) ^ tmp;
        data += 2*sizeof (uint16_t);
        hash += hash >> 11;
    }
  
    /* Handle end cases */
    switch (rem) {
        case 3: hash += get16bits (data);
            hash ^= hash << 16;
            hash ^= ((signed char)data[sizeof (uint16_t)]) << 18;
            hash += hash >> 11;
            break;
        case 2: hash += get16bits (data);
            hash ^= hash << 11;
            hash += hash >> 17;
            break;
        case 1: hash += (signed char)*data;
            hash ^= hash << 10;
            hash += hash >> 1;
    }
  
    /* Force "avalanching" of final 127 bits */
    hash ^= hash << 3;
    hash += hash >> 5;
    hash ^= hash << 4;
    hash += hash >> 17;
    hash ^= hash << 25;
    hash += hash >> 6;
  
    return hash;
}

LinearProbingResolver.cpp

#include "HashTable.hpp"
#include "CollisionResolver.hpp"

LinearProbingResolver::LinearProbingResolver(std::shared_ptr<CollisionCounter> counter)
: counter(counter) {
}

void LinearProbingResolver::add(HashTable* map, HashEntry* entry, int index) {
    // collision. look for a new slot by linear probing.
    int begin = 0;
    auto capacity = map->capacity;
    auto key = entry->player.key();
  
    // update the existing entry
    if (map->table[index]->player.areSame(entry->player)) {
        map->table[index]->player.addMoreInfo(entry->player);
        return;
    }
  
    // track the add collisions
    if (counter) counter->addCollisions++;
  
    while (begin++ < capacity) {
        // new entry
        if (!map->table[index]) {
            map->table[index] = entry;
            return;
        }
      
        // update the existing entry
        if (map->table[index]->player.areSame(entry->player)) {
            map->table[index]->player.addMoreInfo(entry->player);
            return;
        }
//      
//        if (map->table[index]->player.key() == entry->player.key()) {
//            map->table[index]->player.show();
//            entry->player.show();
//        }
//      
        index = (index+1) % capacity;
      
        // track the lookup
        if (counter) counter->lookupCollisions++;
    }
  
    cout << "(linear probe): No free spot available for :" << entry->player.key() << endl;
}

std::unique_ptr<PlayerInfo> LinearProbingResolver::get(HashTable* map, string key, int index){
    auto begin = 0;
    auto capacity = map->capacity;
  
    while (begin++ < capacity) {
        if (map->table[index] && map->table[index]->player.key() == key)
            return std::unique_ptr<PlayerInfo>(new PlayerInfo(map->table[index]->player));
        index = (index+1) % capacity;
      
        // track the look up collisions
        if (counter) counter->lookupCollisions++;
    }
  
    return std::unique_ptr<PlayerInfo>(new NullPlayerInfo());
}

void LinearProbingResolver::Delete(HashEntry* entry) {
    delete entry;
}

LinearProbingResolver::~LinearProbingResolver() {
    // linear probe doesn't own collision counter.
    // So it shouldn't free it up! Just lose reference.
    counter = nullptr;
}
PlayerInfo.cpp

#include "PlayerInfo.hpp"

#include <sstream>
#include <iostream>

using namespace std;

PlayerInfo::PlayerInfo(const PlayerInfo& rhs) {
    teams = rhs.teams;
    playerId = rhs.playerId;
    firstName = rhs.firstName;
    lastName = rhs.lastName;
    birthYear = rhs.birthYear;
    birthCountry = rhs.birthCountry;
    weight = rhs.weight;
    height = rhs.height;
    bats = rhs.bats;
    throws = rhs.throws;
}

PlayerInfo::~PlayerInfo() {
  
}

PlayerInfo PlayerInfo::ConstructFrom(string line) {
    stringstream lineStream(line);
  
    // Format of the line:
    // yearID       : int
    // teamID       : string
    // leagueID     : string
    // playerID     : string
    // salary       : long
    // firstName    : string
    // lastName     : string
    // birthYear    : string
    // birthCountry : string
    // weight       : float
    // height       : float
    // bats         : int
    // throws       : int
  
    int yearId;
    char bats, throws;
    long salary;
    float weight, height;
    string teamId, playerId, leagueId, firstName, lastName, birthYear, birthCountry;
    char ignoreComma;
  
    lineStream >> yearId;       lineStream >> ignoreComma;
    // lineStream >> teamId;       lineStream >> ignoreComma;
    std::getline(lineStream, teamId, ',');
    // lineStream >> leagueId;     lineStream >> ignoreComma;
    std::getline(lineStream, leagueId, ',');
    // lineStream >> playerId;     lineStream >> ignoreComma;
    std::getline(lineStream, playerId, ',');
    lineStream >> salary;       lineStream >> ignoreComma;
    // lineStream >> firstName;    lineStream >> ignoreComma;
    std::getline(lineStream, firstName, ',');
    // lineStream >> lastName;     lineStream >> ignoreComma;
    std::getline(lineStream, lastName, ',');
    // lineStream >> birthYear;    lineStream >> ignoreComma;
    std::getline(lineStream, birthYear, ',');
    // lineStream >> birthCountry; lineStream >> ignoreComma;
    std::getline(lineStream, birthCountry, ',');
    lineStream >> weight;       lineStream >> ignoreComma;
    lineStream >> height;       lineStream >> ignoreComma;
    lineStream >> bats;         lineStream >> ignoreComma;
    lineStream >> throws;
  
    TeamInfo teamInfo = {
        .yearId = yearId,
        .teamId = teamId,
        .leagueId = leagueId,
        .salary = salary
    };
  
    return {
        {teamInfo},
        playerId,
        firstName,
        lastName,
        birthYear,
        birthCountry,
        weight,
        height,
        bats,
        throws
    };
}

bool PlayerInfo::areSame(const PlayerInfo& player) const {
    return uid() == player.uid();
}

const string PlayerInfo::uid() const {
    // generate a unique identifier for this player.
    // Firstname, lastName, birth year, birth country, weight and height uniquely identifies a player.
    // Can i compare based on player Id ?
    auto uid = (
            firstName + lastName + birthYear + birthCountry + std::to_string(weight) + std::to_string(height)
    );
  
    // convert to lower
    std::transform(uid.begin(), uid.end(), uid.begin(), ::tolower);
    return uid;
}

void PlayerInfo::show() const {
    cout << endl;
  
    cout << "First name: "      << firstName        << endl;
    cout << "Last name: "       << lastName         << endl;
    cout << "Year born: "       << birthYear        << endl;
    cout << "Country born: "    << birthCountry     << endl;
    cout << "Weight: "          << weight           << endl;
    cout << "Height: "          << height           << endl;
    cout << "Bats: "            << bats             << endl;
    cout << "Throws: "          << throws           << endl;
  
    cout << "Teams and salary:" << endl;
    for (auto& teamInfo : teams) {
        cout << teamInfo.yearId << "," << teamInfo.teamId << "," << teamInfo.leagueId << ","
             << teamInfo.salary << endl;
    }
  
    cout << endl;
}

void PlayerInfo::addMoreInfo(const PlayerInfo& samePerson) {
    for (auto teamInfo : samePerson.teams)
        teams.push_back(teamInfo);
}

string PlayerInfo::MakeKey(string firstName, string lastName) {
    //    if (firstName == "" && lastName == "")
    //        throw runtime_error("Cannot have a key with first and last name as empty!");
    return firstName + lastName;
}

string PlayerInfo::MakeKey(PlayerInfo& player) {
    return MakeKey(player.firstName, player.lastName);
}

string PlayerInfo::key() const {
    return MakeKey(firstName, lastName);
}
PlayerInfo.hpp

#ifndef PlayerInfo_hpp
#define PlayerInfo_hpp

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct TeamInfo {
    string teamId;
    string leagueId;
    int yearId;
    long salary;
};

class PlayerInfo {
public:
    PlayerInfo() {}
    PlayerInfo(vector<TeamInfo> teams, string playerId, string firstName, string lastName,
               string birthYear, string birthCountry, float weight, float height, char bats, char throws)
    : teams(teams), playerId(playerId), firstName(firstName), lastName(lastName), birthYear(birthYear),
    birthCountry(birthCountry), weight(weight), height(height), bats(bats), throws(throws)
    { }
  
    PlayerInfo(const PlayerInfo& );
    ~PlayerInfo();
  
    char bats;
    char throws;
  
    float weight;
    float height;
  
    vector<TeamInfo> teams;
  
    string playerId;
    string firstName;
    string lastName;
    string birthYear;
    string birthCountry;
  
    string key() const;
    bool areSame(const PlayerInfo&) const;
    const string uid() const;
    void addMoreInfo(const PlayerInfo& samePerson);
  
    virtual void show() const;

    static PlayerInfo ConstructFrom(string line);
    static string MakeKey(string firstName, string lastName);
    static string MakeKey(PlayerInfo& player);
};

class NullPlayerInfo : public PlayerInfo {
public:
    NullPlayerInfo() {}
    virtual void show() const override {
        cout << "Record not found!" << endl;
    }
};

#endif /* PlayerInfo_hpp */

CollisionResolver.hpp

#ifndef CollisionResolver_hpp
#define CollisionResolver_hpp

#include <string>

#include "CollisionCounter.hpp"

using namespace std;

// forward declaration to avoid cyclic reference
class PlayerInfo;
class HashTable;
class HashEntry;

// base class for all type of collision resolvers.
class CollisionResolver {
public:
    virtual void add(HashTable* map, HashEntry* entry, int index) = 0;
    virtual std::unique_ptr<PlayerInfo> get(HashTable* map, string key, int index) = 0;
    virtual void Delete(HashEntry* entry) = 0;
  
    virtual ~CollisionResolver() { }
};

// open addressing (using linear probing)
class LinearProbingResolver : public CollisionResolver {
private:
    std::shared_ptr<CollisionCounter> counter;
  
public:
    LinearProbingResolver(std::shared_ptr<CollisionCounter> counter = nullptr);
  
    virtual void add(HashTable* map, HashEntry* entry, int index) override;
    virtual std::unique_ptr<PlayerInfo> get(HashTable* map, string key, int index) override;
    virtual void Delete(HashEntry* entry) override;
  
    virtual ~LinearProbingResolver();
};

// collsion resolution using chaining
class ChainingResolver : public CollisionResolver {
private:
    std::shared_ptr<CollisionCounter> counter;
  
public:
    ChainingResolver(std::shared_ptr<CollisionCounter> counter = nullptr);
  
    virtual void add(HashTable* map, HashEntry* entry, int index) override;
    virtual std::unique_ptr<PlayerInfo> get(HashTable* map, string key, int index) override;
    virtual void Delete(HashEntry* entry) override;
  
    virtual ~ChainingResolver();
};

#endif /* CollisionResolver_hpp */

CollisionCounter.hpp

#ifndef CollisionCounter_hpp
#define CollisionCounter_hpp

#include <string>
#include <iostream>

using namespace std;

class CollisionCounter {
private:
    string counterName;
  
public:
    int addCollisions;
    int lookupCollisions;

    CollisionCounter(string name)
    : counterName(name) {
    }
  
    // made inline for performance
    inline void resetCounters() {
        addCollisions = 0;
        lookupCollisions = 0;
    }
  
    inline void showAddCollisions() {
        cout << counterName << " add collisions: " << addCollisions << endl;
    }
  
    inline void showlookupCollisions() {
        cout << counterName << " lookup collisions: " << lookupCollisions << endl;
    }
};

#endif /* CollisionCounter_hpp */

Chaining.cpp
#include <iostream>

#include "HashTable.hpp"
#include "PlayerInfo.hpp"
#include "CollisionResolver.hpp"

ChainingResolver::ChainingResolver(std::shared_ptr<CollisionCounter> counter)
: counter(counter) {
  
}

std::unique_ptr<PlayerInfo> ChainingResolver::get(HashTable* map, string key, int index) {
    auto entry = map->table[index];
    while (entry) {
        if (entry->player.key() == key) {
            return std::unique_ptr<PlayerInfo>(new PlayerInfo(entry->player));
        }
      
        entry = entry->next;
  
        // track the look up collisions
        if (counter) counter->lookupCollisions++;
    }
  
    return std::unique_ptr<PlayerInfo>(new NullPlayerInfo());
}

void ChainingResolver::add(HashTable* map, HashEntry* entry, int index) {
    auto collidedEntry = map->table[index];
  
    // match at the last entry ?
    if (collidedEntry->player.areSame(entry->player)) {
        collidedEntry->player.addMoreInfo(entry->player);
        return;
    }
  
    // track the add collisions
    if (counter) counter->addCollisions++;
  
    while (!collidedEntry->player.areSame(entry->player) && collidedEntry->next) {
        collidedEntry = collidedEntry->next;
      
        // track the searchs
        if (counter) counter->lookupCollisions++;
    }
  
    // match at the last entry ?
    if (collidedEntry->player.areSame(entry->player)) {
        collidedEntry->player.addMoreInfo(entry->player);
    } else {
        // no match found. just add it at the end of list.
        collidedEntry->next = entry;
    }
}

void ChainingResolver::Delete(HashEntry* entry) {
    auto prev = entry;
    if (entry) {
        entry = entry->next;
        delete prev;
        prev = entry;
    }
}

ChainingResolver::~ChainingResolver() {
    // chaining resolver doesn't own collision counter.
    // so don't free it. just lose the ref.
    counter = nullptr;
}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote