Compare commits

...

3 Commits

Author SHA1 Message Date
30ad8892de
9.14 Lab: Hash ADT
Now that you have a working implementation of the HashNode and HashTable classes, you can convert them to templates, and update main.cpp to match with the new template classes.

In order for everything to work you will also have to:

- overload the == operator for the Student class
- declare the hash function a friend function of the Student class
- send the hash function as an argument to insert, remove, and search functions.
2024-05-11 16:44:34 -07:00
b43f08aacc
9.13 Lab: Hashing - Linear Probe (insert, search, delete)
Reuse code from the previous lab and write new code as described below:

- search hash: Modify this function to return -1 if the target key is not found or the number of collisions for that key if found.

`int search(Student &target, string key);`

- remove hash: Create a new function to delete an item from the hash table.
- insert manager: inserts user provided data into the hash table and rejects duplicates.
2024-05-11 16:16:27 -07:00
3d112946f5
9.12 Lab: Hashing - Linear Probe (insert, search)
Hash Function: Add the ASCII values of all characters in the key string and return the reminder obtained when divided by the size of the table.

Example: If key = "Bob", and size = 53, we get (66 + 111 + 98) % 53 => 275 % 53 => 10.

Collision Resolution Method: Linear Probe.

The assignment consists of the following classes/files:

- main.cpp (incomplete)
- Student.h (given)
- HashNode.h (given)
- HashTable.h (given)
- HashTable.cpp (incomplete)

Read and understand the given code then write two functions:

- insert hash
- search hash
2024-05-11 15:43:39 -07:00
14 changed files with 492 additions and 0 deletions

8
06-hash-tables/.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
06-hash-tables/.idea/.name generated Normal file
View File

@ -0,0 +1 @@
06_hash_tables

2
06-hash-tables/.idea/06-hash-tables.iml generated Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

4
06-hash-tables/.idea/misc.xml generated Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
06-hash-tables/.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/06-hash-tables.iml" filepath="$PROJECT_DIR$/.idea/06-hash-tables.iml" />
</modules>
</component>
</project>

6
06-hash-tables/.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.28)
project(06_hash_tables)
set(CMAKE_CXX_STANDARD 20)
add_executable(06_hash_tables main.cpp
Student.cpp)

50
06-hash-tables/HashNode.h Normal file
View File

@ -0,0 +1,50 @@
// Specification file for the HashNode class
// Written By: Iurii Tatishchev
// Changed by: Iurii Tatishchev
#ifndef _HASH_NODE
#define _HASH_NODE
// To do: convert to a template
template<typename T>
class HashNode {
private:
T item;
int occupied; // 1 -> occupied, 0 -> empty from start, -1 -> empty after removal
int noCollisions;
public:
// constructors
HashNode() {
occupied = 0;
noCollisions = 0;
}
HashNode(T anItem) {
item = anItem;
occupied = 1;
noCollisions = 0;
}
HashNode(T anItem, int ocp, int nCol) {
item = anItem;
occupied = ocp;
noCollisions = nCol;
}
// setters
void setItem(const T &anItem) { item = anItem; }
void setOccupied(int ocp) { occupied = ocp; }
void setNoCollisions(int nCol) { noCollisions = nCol; }
// getters
T getItem() const { return item; }
int getOccupied() const { return occupied; }
int getNoCollisions() const { return noCollisions; }
};
#endif

View File

@ -0,0 +1,81 @@
// Implementation file for the Hash class
// Written By: Iurii Tatishchev
// Changed by: Iurii Tatishchev
#include <string>
#include <utility>
#include "HashTable.h"
using namespace std;
/*~*~*~*
A simple hash function
*~**/
int HashTable::_hash(string key) const {
int sum = 0;
for (char c : key)
sum += c;
return sum % hashSize;
};
/*~*~*~*
hash insert - linear probe
*~**/
bool HashTable::insert(const Student &itemIn) {
if (count == hashSize)
return false;
int pos = _hash(itemIn.getName());
int collisions = 0;
while (hashAry[pos].getOccupied() == 1) {
++pos;
++collisions;
pos = pos % hashSize;
}
hashAry[pos].setItem(itemIn);
hashAry[pos].setOccupied(1);
hashAry[pos].setNoCollisions(collisions);
count++;
return true;
}
/*~*~*~*
hash delete - linear probe
*~**/
bool HashTable::remove(Student &itemOut, string key) {
int pos = _hash(key);
for (int collisions = 0; collisions < count; collisions++) {
if (hashAry[pos].getOccupied() == 1 && hashAry[pos].getItem().getName() == key) {
itemOut = hashAry[pos].getItem();
// -1 means freed
hashAry[pos].setOccupied(-1);
count--;
return true;
}
pos = (pos + 1) % hashSize;
}
return false;
}
/*~*~*~*
hash search - linear probe
search for key
if found:
- copy data to itemOut
- copy number of collisions for this key to noCol
- returns true
if not found, returns false
*~**/
int HashTable::search(Student &itemOut, string key) const {
int pos = _hash(key);
for (int collisions = 0; collisions < count; collisions++) {
if (hashAry[pos].getOccupied() == 0) return -1;
if (hashAry[pos].getOccupied() == 1 && hashAry[pos].getItem().getName() == key) {
itemOut = hashAry[pos].getItem();
return hashAry[pos].getNoCollisions();
}
pos = (pos + 1) % hashSize;
}
return -1;
}

120
06-hash-tables/HashTable.h Normal file
View File

@ -0,0 +1,120 @@
// Specification file for the Hash class
// Written By: Iurii Tatishchev
// Changed by: Iurii Tatishchev
#ifndef HASHTABLE_H_
#define HASHTABLE_H_
#include "HashNode.h"
template<class ItemType>
class HashTable {
private:
HashNode<ItemType> *hashAry;
int hashSize;
int count;
public:
HashTable() {
count = 0;
hashSize = 53;
hashAry = new HashNode<ItemType>[hashSize];
}
HashTable(int n) {
count = 0;
hashSize = n;
hashAry = new HashNode<ItemType>[hashSize];
}
~HashTable() { delete[] hashAry; }
int getCount() const { return count; }
int getSize() const { return hashSize; }
double getLoadFactor() const { return 100.0 * count / hashSize; }
bool isEmpty() const { return count == 0; }
bool isFull() const { return count == hashSize; }
bool insert(const ItemType &itemIn, int h(const ItemType &key, int size));
bool remove(ItemType &itemOut, const ItemType &key, int h(const ItemType &key, int size));
int search(ItemType &itemOut, const ItemType &key, int h(const ItemType &key, int size)) const;
};
/*~*~*~*
Insert an item into the hash table
It does not reject duplicates
*~**/
template<class ItemType>
bool HashTable<ItemType>::insert(const ItemType &itemIn, int h(const ItemType &key, int size)) {
if (count == hashSize)
return false;
int pos = h(itemIn, hashSize);
int collisions = 0;
while (hashAry[pos].getOccupied() == 1) {
++pos;
++collisions;
pos = pos % hashSize;
}
hashAry[pos].setItem(itemIn);
hashAry[pos].setOccupied(1);
hashAry[pos].setNoCollisions(collisions);
count++;
return true;
}
/*~*~*~*
Removes the item with the matching key from the hash table
if found:
- copies data in the hash node to itemOut
- replaces data in the hash node with an empty record (occupied = -1: deleted!)
- returns true
if not found:
- returns false
*~**/
template<class ItemType>
bool HashTable<ItemType>::remove(ItemType &itemOut, const ItemType &key, int h(const ItemType &key, int size)) {
int pos = h(key, hashSize);
for (int collisions = 0; collisions < count; collisions++) {
if (hashAry[pos].getOccupied() == 1 && hashAry[pos].getItem() == key) {
itemOut = hashAry[pos].getItem();
// -1 means freed
hashAry[pos].setOccupied(-1);
count--;
return true;
}
pos = (pos + 1) % hashSize;
}
return false;
}
/*~*~*~*
hash search - linear probe
if found:
- copy data to itemOut
- returns the number of collisions for this key
if not found, returns -1
*~**/
template<class ItemType>
int HashTable<ItemType>::search(ItemType &itemOut, const ItemType &key, int h(const ItemType &key, int size)) const {
int pos = h(key, hashSize);
for (int collisions = 0; collisions < count; collisions++) {
if (hashAry[pos].getOccupied() == 0) return -1;
if (hashAry[pos].getOccupied() == 1 && hashAry[pos].getItem() == key) {
itemOut = hashAry[pos].getItem();
return hashAry[pos].getNoCollisions();
}
pos = (pos + 1) % hashSize;
}
return -1;
}
#endif // HASHTABLE_H_

View File

@ -0,0 +1,16 @@
// Implementation file for the Student class
// Written By: Iurii Tatishchev
#include <string>
#include "Student.h"
/*~*~*~*
Hash function: takes the key and returns the index in the hash table
*~**/
int key_to_index(const Student &key, int size) {
string k = key.name;
int sum = 0;
for (int i = 0; k[i]; i++)
sum += k[i];
return sum % size;
};

46
06-hash-tables/Student.h Normal file
View File

@ -0,0 +1,46 @@
// Specification file for the Student class
// Modified by: Iurii Tatishchev
// IDE: CLion
#ifndef STUDENT_H
#define STUDENT_H
using std::string;
class Student; // Forward Declaration
// Function Prototypes for friend functions
int key_to_index(const Student &key, int size);
class Student {
private:
double gpa;
string name;
public:
Student() {
name = "";
gpa = -1;
} // Constructor
Student(string n, double g) {
name = n;/* Write your code here */
gpa = g;
} // Overloaded Constructor
// Setters and getters
void setName(string n) { name = n; }
void setGpa(double g) { gpa = g; }
string getName() const { return name; }
double getGpa() const { return gpa; }
// Overloaded operators
bool operator==(const Student& other) { return name == other.name; }
// friend functions
friend int key_to_index(const Student& key, int size);
};
#endif

137
06-hash-tables/main.cpp Normal file
View File

@ -0,0 +1,137 @@
/*
CIS 22C
Hash Tables ADT - Linear Probe
Written By: Iurii Tatishchev
Reviewed & Modified by: Iurii Tatishchev
*/
#include <iostream>
#include "HashTable.h"
#include "Student.h"
using namespace std;
void buildHash(HashTable<Student> &hash);
void searchManager(const HashTable<Student> &hash);
void deleteManager(HashTable<Student> &hash);
void insertManager(HashTable<Student> &hash);
int main() {
HashTable<Student> hash;
buildHash(hash);
cout << "Load Factor: " << hash.getLoadFactor() << endl;
searchManager(hash);
deleteManager(hash);
insertManager(hash);
return 0;
}
/* **************************************************
This function builds a hash table with data from an array
It calls the insert() function that inserts the new data at the right location in the hash table.
************************************************** */
void buildHash(HashTable<Student> &hash) {
Student list[] = {{"Tom", 2.5},
{"Bob", 3.2},
{"Boc", 3.2},
{"Linda", 3.9},
{"Tim", 4.0},
{"Vic", 3.9},
{"Ann", 3.5},
{"Dylan", 3.1},
{"obB", 2.2},
{"oBb", 3.7},
{"Bbo", 3.3},
{"bBo", 3.9},
{"boB", 2.3},
{"", 0}};
for (int i = 0; list[i].getName() != ""; i++) {
hash.insert(list[i], key_to_index);
}
}
/* **************************************************
This function searches a hash table with user provided data.
It calls the hash search function in a loop.
To stop searching enter "#"
************************************************** */
void searchManager(const HashTable<Student> &hash) {
cout << endl << "~*~ Test Search ~*~" << endl;
cout << "Enter name [# to stop searching]:" << endl;
string name;
getline(cin, name);
while (name != "#") {
Student item;
item.setName(name);
int nc = hash.search(item, item, key_to_index);
if (nc != -1) {
cout << item.getName() << " " << item.getGpa() << " (" << nc << " collisions!)" << endl;
} else {
cout << name << " not found!" << endl;
}
getline(cin, name);
}
cout << "Load Factor: " << hash.getLoadFactor() << endl;
}
/* **************************************************
This function deletes user provided data data from a hash table
It calls the hash delete function in a loop.
To stop deleting enter "#"
************************************************** */
void deleteManager(HashTable<Student> &hash) {
cout << endl << "~*~ Test Delete ~*~" << endl;
cout << "Enter name [# to stop deleting]:" << endl;
string name;
getline(cin, name);
while (name != "#") {
Student itemOut;
itemOut.setName(name);
if (hash.remove(itemOut, itemOut, key_to_index)) {
cout << itemOut.getName() << " " << itemOut.getGpa() << " - deleted!" << endl;
} else {
cout << name << " not found!" << endl;
}
getline(cin, name);
}
cout << "Load Factor: " << hash.getLoadFactor() << endl;
}
/* **************************************************
This function inserts user provided data into the hash table
It rejects duplicates.
It calls hash search and hash insert in a loop.
To stop getting user input enter "#"
************************************************** */
void insertManager(HashTable<Student> &hash) {
cout << endl << "~*~ Test Insert - reject duplicates ~*~" << endl;
cout << "Enter name [# to stop reading]:" << endl;
string name;
getline(cin, name);
while (name != "#") {
Student found;
found.setName(name);
if (hash.search(found, found, key_to_index) != -1) {
cout << "Duplicate key: " << found.getName() << " - rejected!" << endl;
} else {
cout << "Enter gpa:" << endl;
double gpa;
cin >> gpa;
cin.ignore();
Student newStudent(name, gpa);
hash.insert(newStudent, key_to_index);
cout << name << " - inserted (" << hash.search(found, newStudent, key_to_index) << " collisions)" << endl;
}
cout << "Enter name [# to stop reading]:" << endl;
getline(cin, name);
}
cout << "Load Factor: " << hash.getLoadFactor() << endl;
}