-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from Shu-AFK/main
Add hash_table class, associated tests, and tutorial documentation
- Loading branch information
Showing
4 changed files
with
264 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,6 +67,7 @@ | |
"regex": "cpp", | ||
"set": "cpp", | ||
"thread": "cpp", | ||
"random": "cpp" | ||
"random": "cpp", | ||
"list": "cpp" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
``` |