reHashing a table - c++

I am trying to rehash a table by deleting old table and creating a new bigger table with same contents. I created a reHash function, but this function gives memory leaks, causing the program to crash when the function is executed. I can't find my error.
void HashMap::reHash()
{
int OldCapacity = cap;
cap = cap * 2 + 1; //set new capacity
Node** newHashTable = new Node*[cap]; //create a temporary table to hold info
for (int i = 0; i < cap; i++)
{
newHashTable[i] = nullptr;
}
const Node* n;
//fill in the new temp table with old info
for (int i = 0; i < OldCapacity; ++i)
{
n = HashTable[i];
while (n != nullptr)
{
//initialize new node
Node* nod = new Node;
nod->key = n->key;
nod->value = n->value;
nod->next = nullptr;
Node*& bucket = newHashTable[default_hash_function(n->key)/cap];
nod->next = bucket;
bucket = nod;
n = n->next;
}
}
// delete the links
for (int i = 0; i < OldCapacity; ++i)
{
Node *curr = HashTable[i];
Node *next;
while (curr != nullptr)
{
next = curr->next;
delete curr;
curr = next;
}
}
HashTable = newHashTable;
}

Your fundamental leak is this:
HashTable = newHashTable;
You never deleted the old pointer-array. It should be this:
delete [] HashTable;
HashTable = newHashTable;
You also aren't computing the modulo of your hash function correctly for your table size in the reassignment, which would be devastating to your hash table.
This:
Node*& bucket = newHashTable[default_hash_function(tmp->key) / cap];
should be this:
Node*& bucket = newHashTable[default_hash_function(tmp->key) % cap];
// note modulo operator -------------------------------------^
Rehash Sans-Allocations
Honestly, none of the dynamic allocations are needed in this except allocating the new bed. You can use the existing nodes by moving them from the old bed to the new one.
void HashMap::reHash()
{
int OldCapacity = cap;
cap = cap * 2 + 1;
// allocate new bed. note: uses () to value-initialize nullptr entries
Node** newHashTable = new Node*[cap]();
//fill in the new temp table with old info
for (int i = 0; i < OldCapacity; ++i)
{
Node *n = HashTable[i];
while (n != nullptr)
{
// advance n *before* moving node to new hash bed
Node *tmp = n;
n = n->next;
// find the proper collision list pointer.
Node*& bucket = newHashTable[default_hash_function(tmp->key) % cap];
tmp->next = bucket;
bucket = tmp;
}
}
delete [] HashTable;
HashTable = newHashTable;
}

Related

Hash table - issue with destructor (pointer being freed was not allocated)

I have a HashTable, where collisions are handled by chaining (linked lists). The first node of every linked list has a pointer from each array position. Shown below is a regular constructor along with rule of 3 functions.
Although my code is compiling and my functions (add, remove, etc) are producing the right output, I am having an issue with the destructor (the IDE points to it with a Thread 1: signal SIGABRT) and the console displays "pointer being freed was not allocated" after my driver program finishes running. I can't figure out what went wrong so any help would be appreciated. I did not include my code for any of the other functions (add, remove, etc) aside from constructors/destructors.
Even when I comment out the copy and overloaded= constructors, the same issue still arise with the destructor.
specification:
class HashTable {
public:
HashTable(int);
~HashTable();
HashTable(const HashTable &);
HashTable& operator=(const HashTable &);
private:
struct Node {
string word;
int wordCount;
Node * next;
// node constructor
Node(string w, int count) {
word = w;
wordCount = count;
next = nullptr;
}
};
Node** wordList;
int capacity;
int hashFunction(string);
};
Implementation of big 4:
constructor:
HashTable::HashTable(int cap) {
capacity = cap;
wordList = new Node*[capacity];
for (int i = 0; i < capacity; i++)
wordList[i] = nullptr;
}
destructor (where the problem seems to be)
HashTable::~HashTable() {
for (int i = 0; i < capacity; i++) {
Node* curr = wordList[i];
while (curr != nullptr) {
Node* prev = curr;
curr = curr->next;
delete prev;
}
}
delete[] wordList;
}
copy constructor:
HashTable::HashTable(const HashTable &obj) {
capacity = obj.capacity;
wordList = new Node*[capacity];
for (int i = 0; i < capacity; i++) {
if (obj.wordList[i] == nullptr)
continue;
Node * newNode = new Node(obj.wordList[i]->word,
obj.wordList[i]->wordCount);
wordList[i] = newNode;
}
}
copy assignment operator:
HashTable& HashTable::operator=(const HashTable &obj) {
if (this != &obj) {
for (int i = 0; i < capacity; i++) {
Node* curr = wordList[i];
while (curr != nullptr) {
Node* prev = curr;
curr = curr->next;
delete prev;
}
}
delete[] this->wordList;
this->capacity = obj.capacity;
this->wordList = new Node*[capacity];
for (int i = 0; i < this->capacity; i++) {
if (obj.wordList[i] == nullptr)
continue;
Node * newNode = new Node(obj.wordList[i]->word,
obj.wordList[i]->wordCount);
this->wordList[i] = newNode;
}
}
return *this;
}
In your copy constructor and copy assignment operator, you are copying the list pointers from obj into this. This leaves the same pointers in both objects, resulting in double free and other issues once one HashTable has been freed,
When you do the copies, you need to do a Deep Copy, which is to allocate new nodes for the copy of the word list.

C++, Array of pointers, pointing to entries in a doubly linked list

I currently have a linked list that has been created and needs an array of pointers to each item in the list so that it can be sorted and manipulated.
using namespace std;
struct Node {
float tries;
float vals;
Node* next;
Node* prev;
};
class doList {
public:
doList(float attempts[], float values[], int numElements) {
Node* current;
current = new Node;
current->tries = attempts[0];
current->vals = values[0];
current->prev = NULL;
head = current;
tail = current;
for (int d = 1; d < numElements; d++) {
current = new Node;
current->tries = attempts[d];
current->vals = values[d];
current->prev = tail;
tail->next = current;
tail = current;
if (d == (numElements - 1)) {
tail->next = NULL;
}
}
arrayPointers = new Node*[numElements];
}
private:
Node* head;
Node* tail;
Node** arrayPointers;
};
I tried to use a private element to make the array of pointers and allocated space for it, but not sure how to work with it besides that. Have to do it without including any other options.
EDIT
Sorry I was not clear enough. I am confused on how to use the array of pointers to the linked list. I need help figuring out how to store the nodes in an array of pointers. Essentially I need to have an array where the elements in the array point to entries in the list.
You will want to create the array beforehand and store the pointer to each element at creation time.
doList(float attempts[], float values[], int numElements) {
arrayPointers = new Node*[numElements];
Node* current;
current = new Node;
current->tries = attempts[0];
current->vals = values[0];
current->prev = NULL;
head = current;
tail = current;
arrayPointers[0] = current;
for (int d = 1; d < numElements; d++)
{
current = new Node;
current->tries = attempts[d];
current->vals = values[d];
current->prev = tail;
tail->next = current;
tail = current;
arraypointers[d] = current;
if (d == (numElements - 1))
{
tail->next = NULL;
}
}
}

Clearing a hash table in C++

I have create a clear () function, which when is called, clears the entire Hash Table and resets the size to 0. The function is causing memory leaks in my program but I do not see a possible leak..
Here is my clear() function:
void HashMap::clear()
{
unsigned int capacity = HashMap::bucketCount();
for (unsigned int i = 0; i < capacity; i++)
{
Node* temp;
Node* StoreThenDel = new Node;
if (HashTable[i] != nullptr)
{
temp = HashTable[i];
HashTable[i] = nullptr;
while(temp->next != nullptr)
{
StoreThenDel = temp;
if(StoreThenDel->next != nullptr)
temp = StoreThenDel->next;
delete StoreThenDel;
}
}
}
sz=0; // reset size
}
You do a StoreThenDel = new Node. This allocates memory for a Node on the heap. Afterwards you do a StoreThenDel = temp, losing the information about where you allocated memory for the Node on the heap.
Your while loop and temp variables are just very confusing, try to simplify the code to something like the below and you will find that the simpler code has fewer problems.
for (unsigned int i = 0; i < capacity; ++i)
{
while (HashTable[i] != nullptr)
{
Node* temp = HashTable[i];
HashTable[i] = temp->next;
delete temp;
}
}
Node* StoreThenDel = new Node;
This new is a leak and is unnecessary.
while(temp->next != nullptr)
This loop condition stops too soon. It should run until temp != nullptr. As is it leaks the last entry in each list.
if(StoreThenDel->next != nullptr)
temp = StoreThenDel->next;
That assignment of temp should not be conditional.

c++ rehash on a LinkedList of pointers

I have a fully functioning hashMap class and everything seems to be working very well EXCEPT a rehash function designed to create a hashmap when the load factor of the previous hashmap reaches 0.8.
void HashMap::reHash()
{
logins = 0;
numberOfPairs = 0;
Node** newBucket = new Node* [(2 * lengthOfMap) + 1];
for(int i = 0; i < lengthOfMap; i++)
{
Node* oldHead = bucketList[i];
for(Node* temp = oldHead; temp != nullptr; temp = temp-> next)
{
std::string key = oldHead->key;
std::string value = oldHead->value;
unsigned int index = hash(key) % lengthOfMap;
if(newBucket[index] == nullptr)
{
std::cout << "HIT" << std::endl;
newBucket[i] = new Node;
newBucket[i]->key = key;
newBucket[i]->value = value;
newBucket[i]->next = nullptr;
numberOfPairs[index]++;
logins++;
}
else if (bucketList[index] != nullptr)
{
Node* temp = bucketList[index];
while(temp->next != nullptr)
{
temp = temp->next;
}
Node* n = new Node;
n->key = key;
n->value = value;
temp->next = n;
n->next = nullptr;
std::cout << "FAIL at index: " << index << std::endl;
//numberOfPairs[index]++;
logins++;
}
}
}
for(int i = 0; i < lengthOfMap; ++i)
{
if( bucketList[i] )
{
Node* first = bucketList[i];
while( first )
{
Node* temp = first->next;
delete first;
first = temp;
}
}
}
delete bucketList;
bucketList = newBucket;
lengthOfMap = (2 * lengthOfMap) + 1;
}
bucketList[] is my previous array full of Node* which each begin the first link in a linked list. I have added a couple std::cout for my own benefit, and I seem to be stuck in a permanent loop reading FAIL at index:0 over and over again. I will admit I am new to the for loop iterating through the linked list, which I think is the source of my problem, but I'm looking for any helpful input.
Thanks again.

Hash-table - Array of Linked-list - C++

I'm trying to create a Hash-table by using an array on linked-nodes (making a linked list).
But I'm having difficulties inserting a value into the Hash-table. When I run it, I get this:
http://gyazo.com/3a28a70e66b3ea34e08223e5948f49c0.png
Here is my code:
#include <iostream>
using namespace std;
class Node {
public:
int num;
Node * next;
};
class intHashTable {
private:
int size;
Node ** table;
public:
intHashTable(int size); // construct a new hash table with size elements
~intHashTable(); // delete the memory for all internal components
void insert(int num); // insert num into the hash table, no effect
// if num is already in table
void remove(int num); // remove num from the hash table, no effect if not in table
int lookup(int num); // return 1 if num is already in table, 0 otherwise
void print(void); // print the elements of the hash table to the screen
};
// construct a new hash table with nelements elements
intHashTable::intHashTable(int nelements)
{
size = nelements;
table = new Node*[size];
for ( int i = 0; i < size; i++ ) {
table[i] = NULL;
}
}
intHashTable::~intHashTable()
{
for(int i=0; i<size; i++)
{
Node* temp = table[i];
while(temp != NULL)
{
Node* next = temp->next;
delete temp;
temp = next;
}
}
size = 0;
delete[] table;
}
void intHashTable::insert(int num){
int location = ((unsigned)num) % size;
Node *runner = table[location];
if(runner == NULL ){
runner->num = num;
}else{
while(runner != NULL ){
runner = runner->next;
}
runner->num = num;
}
}
int main(){
intHashTable a (10);
a.insert(2);
return 0;
}
After construction of intHashTable, all the elements of table are still NULL. However, in the function insert, one element is dereferenced:
Node *runner = table[location];
runner = runner->next;
This makes the program crash, because it is illegal to dereference a null pointer.
the logic here is wrong
int location = ((unsigned)num) % size;
Node *runner = table[location];
if(runner == NULL ) // if null u dereference it!
{
runner->num = num;
}
else
{
while(runner != NULL ) { // u loop until null
runner = runner->next;
}
runner->num = num; // once u reach null u dereference it!
}
i would suggest instead:
first a ctor for your Node
class Node {
public:
int num;
Node * next;
Node( int _n ) : num(_n), next(NULL) { }
};
and then
if ( runner != NULL )
{
while ( runner->next != NULL )
{
runner = runner->next;
}
runner->next = new Node( num );
}
else
{
table[location] = new Node( num );
}
This code certainly won't work:
if(runner == NULL ){
runner->num = num;
If runner is NULL, then you should never dereference it (using * or -> on it).
Node *runner = table[location];
runner = runner->next;
if(runner == NULL )
You never verified whether table[location] is null. But during construction of your hashtable, there are no nodes inside the node table (you set yourself every entry to null).
The problem with your code is that you never think about allocating your node. You should be doing
Node* toInsert = new Node;
toInsert->next= NULL;
toInsert->num = num;
if(table[location]==NULL){
table[location] = toInsert;
}
else{
Node *runner = table[location];
while(runner->next != NULL){
runner = runner->next;
}
runner->next = toInsert;
}