I am very inexperienced at C++. I wrote a Hash Map which uses chaining for collision resolution. I intentionally did not use smart-pointers, as the objective of this was to learn and showcase. I have tested the code and removed all bugs I came across. I am hoping to get feedback on bad practices and potential risks associated with my code.
HashMap.h
#pragma once
#include <string>
#include "HashElement.h"
class HashMap
{
private:
HashElement **map_;
int size_;
int count_;
public:
HashMap(int);
~HashMap();
int GetHash(int);
void Put(int, std::string);
std::string GetElement(int);
bool Contains(int);
void Remove(int);
int GetCount();
};
HashMap.cpp
#include "HashMap.h"
#include "PrimeChecker.h"
HashMap::HashMap(int size)
{
while (!PrimeChecker::IsPrime(size)){
size++;
}
size_ = size;
map_ = new HashElement*[size_]();
}
HashMap::~HashMap()
{
for (int i = 0; i < size_; i++){
int hash = GetHash(i);
if (!map_[hash]){
continue;
}
HashElement *current_element = map_[hash];
HashElement *next_element = map_[hash];
while (next_element->next_element_){
next_element = next_element->next_element_;
delete current_element;
current_element = next_element;
}
delete current_element;
}
}
int HashMap::GetHash(int key){
return key % size_;
}
void HashMap::Put(int key, std::string value){
int hash = GetHash(key);
if (!map_[hash]){
map_[hash] = new HashElement(key, value);
}
else{
HashElement *last_element = map_[hash];
while (last_element->next_element_){
last_element = last_element->next_element_;
}
last_element->next_element_ = new HashElement(key, value);
}
count_++;
}
std::string HashMap::GetElement(int key){
int hash = GetHash(key);
if (map_[hash]){
HashElement *current_element = map_[hash];
while (current_element->GetKey() != key && current_element->next_element_){
current_element = current_element->next_element_;
}
return current_element->GetValue();
}
return nullptr;
}
bool HashMap::Contains(int key){
int hash = GetHash(key);
if (map_[hash]){
HashElement *current_element = map_[hash];
while (current_element->GetKey() != key && current_element->next_element_){
current_element = current_element->next_element_;
}
if (current_element->GetKey() == key){
return true;
}
}
return false;
}
void HashMap::Remove(int key){
if (!Contains(key)){
return;
}
int hash = GetHash(key);
HashElement *current_element = map_[hash];
if (current_element->GetKey() == key){
map_[hash] = currentElement->next_element_;
delete current_element;
}
else{
HashElement *previous_element = current_element;
current_element = current_element->next_element_;
while (current_element->GetKey() != key){
previous_element = current_element;
current_element = current_element->next_element_;
}
previous_element->next_element_ = current_element->next_element_;
delete current_element;
}
count_--;
}
int HashMap::GetCount(){
return count_;
}
HashElement.h
#pragma once
#include <string>
class HashElement
{
private:
int key_;
std::string value_;
public:
HashElement(int, std::string);
~HashElement();
HashElement *next_element_;
int GetKey();
std::string GetValue();
};
HashElement.cpp
#include "HashElement.h"
HashElement::HashElement(int key, std::string value)
{
key_ = key;
value_ = value;
next_element_ = nullptr;
}
HashElement::~HashElement()
{
}
int HashElement::GetKey(){
return key_;
}
std::string HashElement::GetValue(){
return value_;
}
PrimeChecker.h
#pragma once
namespace PrimeChecker
{
bool IsPrime(int);
}
PrimeChecker.cpp
#include "PrimeChecker.h"
namespace PrimeChecker
{
//This method was adapted from http://en.wikipedia.org/wiki/Primality_test
bool IsPrime(int number)
{
if (number <= 3) {
return number > 1;
}
else if (number % 2 == 0 || number % 3 == 0) {
return false;
}
else {
for (unsigned short i = 5; i * i <= number; i += 6) {
if (number % i == 0 || number % (i + 2) == 0) {
return false;
}
}
return true;
}
}
}