Skip to content

Commit

Permalink
Merge pull request #20 from Shu-AFK/main
Browse files Browse the repository at this point in the history
Add hash_table class, associated tests, and tutorial documentation
  • Loading branch information
spirosmaggioros authored Feb 5, 2024
2 parents efcf278 + cd025bd commit 33f597e
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"regex": "cpp",
"set": "cpp",
"thread": "cpp",
"random": "cpp"
"random": "cpp",
"list": "cpp"
}
}
141 changes: 141 additions & 0 deletions src/classes/hash_table/hash_table.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#ifndef HASH_TABLE_H
#define HASH_TABLE_H

#include <functional>
#include <iostream>
#include <list>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>

/**
* @class hash_table
* @tparam KeyType Type of the keys in the hash table.
* @tparam ValueType Type of the values in the hash table.
*
* @brief A simple implementation of a hash table.
* @details
* This is a templated class for a hash table, a data structure that provides
* fast data retrieval and storage operations based on keys. The template
* parameters are the type of the keys and the type of the values stored in the
* hash table. Keys cannot be duplicate and an insertion of an existing key
* leads to an update of the corresponding value.
*
* The following are the class methods
*
* @note Use only types that can be hashed as the KeyType.
*/
template <typename KeyType, typename ValueType> class hash_table {
public:
/**
* @brief Construct a new hash table object
*
* @param v the initializer vector
*/
hash_table(std::vector<std::pair<KeyType, ValueType>> v = {}) {
if (!v.empty()) {
for (auto &x : v) {
this->insert(x.first, x.second);
}
}
}

/**
* @brief Copy constructor of the hash_table
*
* @param h the hash table we want to copy
*/
hash_table(const hash_table &h) {
bucketList = h.bucketList;
hash = h.hash;
}

/**
* @brief operator = for the hash_table class
* @param h the hash table we want to copy
* @return hash_table&
*/
hash_table &operator=(const hash_table &h) {
bucketList = h.bucketList;
hash = h.hash;
return *this;
}

/**
* @brief Destroy the hash table object
*/
~hash_table() { bucketList.clear(); }

/**
* @brief Inserts a key-value pair into the hash table.
* @details
* This function inserts a key-value pair into the hash table. If a pair with
* the same key already exists, it updates the value.
* @param key The key to insert.
* @param value The value to insert.
*/
void insert(const KeyType &key, const ValueType &value) {
auto &list = bucketList[hash(key)];
for (auto &pair : list) {
if (pair.first == key) {
pair.second = value;
return;
}
}
list.emplace_back(key, value);
}

/**
* @brief Retrieves the value associated with the given key.
* @param key The key to retrieve the value for.
* @return The value associated with the given key, if it exists. Otherwise,
* returns std::nullopt.
*/
std::optional<ValueType> retrieve(const KeyType &key) {
auto &list = bucketList[hash(key)];
for (auto &pair : list) {
if (pair.first == key) {
return pair.second;
}
}
return std::nullopt;
}

/**
* @brief Removes the key-value pair associated with the given key from the
* hash table.
* @details
* This function removes the key-value pair associated with the given key from
* the hash table.
* @param key The key to remove.
*/
void remove(const KeyType &key) {
auto &list = bucketList[hash(key)];
list.remove_if([key](const auto &pair) { return pair.first == key; });
}

/**
* @brief << operator for hash_table class
* @return std::ostream&
*/
friend std::ostream &operator<<(std::ostream &out,
hash_table<KeyType, ValueType> &h) {
out << '[';
for (auto &[key, list] : h.bucketList) {
for (auto &pair : h.bucketList[key]) {
out << "{" << pair.first << ", " << pair.second << "} ";
}
out << '\n';
}
out << ']';
}

private:
std::hash<KeyType> hash;
// std::vector<std::list<std::pair<KeyType, ValueType>>> bucketList;
std::unordered_map<size_t, std::list<std::pair<KeyType, ValueType>>>
bucketList;
};

#endif // HASH_TABLE_H
52 changes: 52 additions & 0 deletions tests/hash_table/hash_table.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#define CATCH_CONFIG_MAIN
#include "../../src/classes/hash_table/hash_table.h"
#include "../catch2/catch.hpp"
#include <string>

TEST_CASE("checking insertions, overriding insertions and retrievals") {
hash_table<std::string, int> table;

table.insert("abc", 1);
table.insert("abc", 2);
table.insert("def", 3);

REQUIRE(table.retrieve("abc") == 2);
REQUIRE(table.retrieve("ghi") == std::nullopt);
}

TEST_CASE("checking removals") {
hash_table<std::string, int> table;

table.insert("abc", 1);
table.insert("def", 2);
table.remove("abc");

REQUIRE(table.retrieve("abc") == std::nullopt);
REQUIRE(table.retrieve("def") == 2);
}

TEST_CASE("testing copy constructor") {
hash_table<int, std::string> table;
table.insert(1, "abc");
table.insert(2, "bcd");
table.insert(3, "cba");

hash_table<int, std::string> table2(table);

for (int i = 1; i <= 3; i++) {
REQUIRE(table.retrieve(i) == table2.retrieve(i));
}
}

TEST_CASE("testing operator =") {
hash_table<int, std::string> table;
table.insert(1, "abc");
table.insert(2, "bcd");
table.insert(3, "cba");

hash_table<int, std::string> table2 = table;

for (int i = 1; i <= 3; i++) {
REQUIRE(table.retrieve(i) == table2.retrieve(i));
}
}
69 changes: 69 additions & 0 deletions tutorial/hash_table.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
### Mini Tutorial for the hash_table class

hash_table -- creates a hash table(dictionary).

### **Create an instance of the hash_table:**:
```cpp
#include <hash_table.h>

hash_table<std::string, int> ht;
// creates a hash table with keys of type std::string and values of type int
```


### **insert**:
```cpp
#include <hash_table.h>

hash_table<std::string, int> ht;
ht.insert("apple", 1);
ht.insert("banana", 2);
ht.insert("carrot", 3);
// inserts key-value pairs {"apple", 1}, {"banana", 2}, {"carrot", 3} into the hash table

```

### **retrieve**:
```cpp
#include <hash_table.h>

hash_table<std::string, int> ht;
ht.insert("apple", 1);
ht.insert("banana", 2);
ht.insert("carrot", 3);

// retrieves the value associated with the given key.
auto opt_value = ht.retrieve("banana");
if(opt_value) {
std::cout << *opt_value << '\n'; // will print 2
} else {
std::cout << "Element not found" << '\n';
}
```

### **remove**:
```cpp
#include <hash_table.h>

hash_table<std::string, int> ht;
ht.insert("apple", 1);
ht.insert("banana", 2);
ht.insert("carrot", 3);

// removes the key-value pair associated with the given key from the hash_table.
ht.remove("carrot");
assert(!ht.retrieve("carrot"));
```
### **printList**:
```cpp
#include <hash_table.h>
hash_table<std::string, int> ht;
ht.insert("apple", 1);
ht.insert("banana", 2);
ht.insert("carrot", 3);
// prints the contents of the hash_table to the console
ht.printList();
```

0 comments on commit 33f597e

Please sign in to comment.