I have to create a very BASIC hash map of Functions pointers. My requirement is just add values in it and then get it based on key. For some political reason, I can not use any standard librabry. I have a code which works fine. But if I want a functions pointers to my CLASS MEMBER FUNCTIONS then this do not work. Any suggestion what should be the modification in below code.
In this PING and REFRESH are independent functions. So this code works. But if I move these functions to HashMap class then it fails.
Code:--
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
using namespace std;
typedef void (*FunctionPtr)();
void ping(){
cout<<"ping";
}
void refresh(){
cout<<"refresh";
}
class HashEntry {
private:
int key;
FunctionPtr func_ptr1;;
public:
HashEntry(int key, FunctionPtr fptr) {
this->key = key;
this->func_ptr1 = fptr;
}
int getKey() {
return key;
}
FunctionPtr getValue() {
return this->func_ptr1;
}
};
const int TABLE_SIZE = 128;
class HashMap {
private:
HashEntry **table;
public:
HashMap() {
table = new HashEntry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
}
FunctionPtr get(int key) {
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] == NULL)
return NULL;
else
return table[hash]->getValue();
}
void put(int key, FunctionPtr fptr) {
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] != NULL)
delete table[hash];
table[hash] = new HashEntry(key, fptr);
}
~HashMap() {
for (int i = 0; i < TABLE_SIZE; i++)
if (table[i] != NULL)
delete table[i];
delete[] table;
}
};
void main(){
HashMap* pHashsMap = new HashMap();
pHashsMap->put(1,ping);
pHashsMap->put(2,refresh);
pHashsMap->put(3,ping);
pHashsMap->put(4,refresh);
pHashsMap->put(5,ping);
pHashsMap->put(6,refresh);
cout<<" Key 1---"<<pHashsMap->get(1)<<endl;
pHashsMap->get(1)();
cout<<" Key 5---"<<pHashsMap->get(5)<<endl;
pHashsMap->get(5)();
cout<<" Key 3---"<<pHashsMap->get(3)<<endl;
pHashsMap->get(3)();
cout<<" Key 6---"<<pHashsMap->get(6)<<endl;
pHashsMap->get(6)();
delete pHashsMap;
}
The smart-alec answer: inspect the code for std::bind, learn from it, and create your own (though tbh, not using STL/boost isn't smart...).
the simpler answer: you need to create a union type to hold your normal function pointer and a class member function pointer, then store a bool to indicate if it is a class pointer:
class funcbind_t
{
union
{
void (*pf)();
void (SomeClass::*mfp)();
};
bool member;
funcbind_t(void (*_pf)()) : pf(_pf), member(false)
{
}
funcbind_t(void (SomeClass::*_mpf)()) : mpf(_mpf), member(true)
{
}
void operator ()()
{
if(member)
mfp();
else
fp();
}
};
as you can see, this is going to get messy when you start needing differing parameters to the functions.
Related
I am practicing the implementation of the hash map in C++. My goal is to ultimately map words to a pair of integers that correspond to their line and column in a text file. I took the hash map implementation from here and build upon that. The code works fine when I pass words with only one letter. However, when I have a word with more than one letter, the code compiles on Visual Studio, but at runtime throughs read access violation at this line:
HashNode<K, V> *entry = table[hashValue];
(within the insert member function). I thought there might be some tweaks that I should consider when using strings in a temple structure that I might not be aware of; however, I couldn't really find itout after hours of searching the web. Any ideas on how to fix this is greatly appreciated.
#include <string>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
#define TABLE_SIZE 1028
template <typename K, typename V>
class HashNode {
public:
HashNode(const K &key, const V &value) :
key(key), value(value), next(NULL) {
}
K getKey() const {
return key;
}
V getValue() const {
return value;
}
void setValue(V value) {
HashNode::value = value;
}
HashNode *getNext() const {
return next;
}
void setNext(HashNode *next) {
HashNode::next = next;
}
private:
// key-value pair
K key;
V value;
// next bucket with the same key
HashNode *next;
};
template <typename K, typename V, typename F = KeyHash<K>>
class HashMap {
public:
HashMap() {
// construct zero initialized hash table of size
table = new HashNode<K, V> * [TABLE_SIZE]();
}
~HashMap() {
// destroy all buckets one by one
for (int i = 0; i < TABLE_SIZE; ++i) {
HashNode<K, V> *entry = table[i];
while (entry != NULL) {
HashNode<K, V> *prev = entry;
entry = entry->getNext();
delete prev;
}
table[i] = NULL;
}
// destroy the hash table
delete[] table;
}
void get(const K &key, vector<V> &value) {
unsigned long hashValue = hashFunc(key);
HashNode<K, V> *entry = table[hashValue];
while (entry != NULL) {
if (entry->getKey() == key) {
value.push_back(entry->getValue());
//return true;
}
entry = entry->getNext();
}
//return false;
}
void insert(const K &key, const V &value) {
unsigned long hashValue = hashFunc(key);
HashNode<K, V> *prev = NULL;
HashNode<K, V> *entry = table[hashValue];
while (entry != NULL && entry->getKey() == key) {
prev = entry;
entry = entry->getNext();
}
if (entry == NULL) {
entry = new HashNode<K, V>(key, value);
if (prev == NULL) {
// insert as first bucket
table[hashValue] = entry;
}
else {
prev->setNext(entry);
}
}
else {
// just update the value
entry->setValue(value);
}
}
void remove(const K &key) {
unsigned long hashValue = hashFunc(key);
HashNode<K, V> *prev = NULL;
HashNode<K, V> *entry = table[hashValue];
while (entry != NULL && entry->getKey() != key) {
prev = entry;
entry = entry->getNext();
}
if (entry == NULL) {
// key not found
return;
}
else {
if (prev == NULL) {
// remove first bucket of the list
table[hashValue] = entry->getNext();
}
else {
prev->setNext(entry->getNext());
}
delete entry;
}
}
private:
// hash table
HashNode<K, V> **table;
F hashFunc;
};
int main()
{
struct MyKeyHash
{
unsigned long operator()(const string & s) const
{
int hash = 7;
for (int i = 0; i < s.length(); i++)
{
hash = hash * 31 + s[i];
}
return hash;
}
};
HashMap<string, tuple<int, int>, MyKeyHash> hmap;
hmap.insert("BB", make_pair(3, 3));
hmap.insert("A", make_pair(1, 2));
hmap.insert("A", make_pair(4, 2));
vector<tuple<int, int>> value;
hmap.get("B", value);
for (auto it : value)
{
cout << get<0>(it) << ", " << get<1>(it) << endl;
}
}
unsigned long hashValue = hashFunc(key);
//...
table[hashValue]
The hashValue is returned from the function
unsigned long operator()(const string & s) const
{
int hash = 7;
for (int i = 0; i < s.length(); i++)
{
hash = hash * 31 + s[i];
}
return hash;
}
which can return arbitrarily large values (in the range of int). But table is an array of length TABLE_SIZE (1028). If the output happens to be larger than that, you are accessing it out-of-bounds.
The way the function is written, this is more likely to happen for longer input strings.
You probably meant
unsigned long hashValue = hashFunc(key)%TABLE_SIZE;
Also note that your hash function overflows, causing undefined behavior (because you are using signed integers), if the string is long enough. You should be using unsigned long instead of int, matching the return type and being unsigned.
You're missing an important step for using the hash map. You've calculated the hash, and you have a table to store things in, but you can't use the hash directly as an index into the table. It needs to be reduced modulo the size of the table to keep the subscript valid.
In this case, after computing the hash (calling the hashFunc member), you need to include
hashValue = hashValue % TABLE_SIZE;
You'll want to eventually add code to determine when you need to grow the size of the hash table, which will require TABLE_SIZE to be a member of the HashMap.
As the title says I am trying to implement Set ADT on a Hashtable with independent lists. The thing is I don't know where I'm wrong.
The code I am about to post is taken from a bigger project and I took just the esential parts of it to show you.
SetADT.h:
#pragma once
#pragma once
#include <stdio.h>
#define CAPACITY 10
using namespace std;
template <typename TElement>
class IteratorSet;
template<typename TElement>
class Set {
class Nod {
public:
TElement element;
Nod* next;
};
public:
Set();
void add(TElement element);
int size();
void sterge(TElement element);
bool cauta(TElement element);
friend class IteratorSet<TElement>;
IteratorSet<TElement> iterator() { return IteratorSet<TElement>(this); }
private:
int dimensiune;
typename Set<TElement>::Nod* prim;
int max;
Nod** table;
int hashFunction(TElement element) { return element.hashCode() % max; }
Nod* set;
};
template<typename TElement>
Set<TElement>::Set()
{
max = CAPACITATE;
table = new Nod*[max];
for (int i = 0; i < max; i++)
table[i] = NULL;
}
template <typename TElement>
void Set<TElement>::add(TElement element)
{
int pozitie = hashFunction(element);
Nod* curent = table[pozitie];
while (curent != NULL && !(element == curent->element))
curent = curent->next;
if (curent != NULL)
return;
else
{
Nod* n = new Nod;
n->element = element;
n->next = table[pozitie];
table[pozitie] = n;
}
dimensiune++;
}
template <typename TElement>
int Set<TElement>::size()
{
return dimensiune;
}
template <typename TElement>
void Set<TElement>::sterge(TElement element)
{
int pozitie = hashFunction(element);
Nod* curent = table[pozitie];
if (table[pozitie] == NULL)
return;
if (table[pozitie]->element == element)
{
Nod* deSters = table[pozitie];
table[pozitie] = table[pozitie]->next;
delete deSters;
dimensiune--;
return;
}
Nod* elem = table[pozitie];
while (elem->next != NULL && (elem->next->element) == element)
elem = elem->next;
if (elem->next != NULL)
{
Nod* deSters = elem->next;
elem->next = elem->next->next;
delete deSters;
dimensiune--;
}
}
template <typename TElement>
bool Set<TElement>::cauta(TElement element)
{
int pozitie = hashFunction(element);
Nod* curent = table[pozitie];
while (curent != NULL && !(element == curent->element))
curent = curent->next;
if (curent != NULL)
{
return true;
}
return false;
}
template<typename TElement>
class IteratorSet {
public:
IteratorSet(Set<TElement>* m);
void next();
bool valid();
TElement element();
private:
Set<TElement>* Set;
typename Set<TElement>::Nod* crt;
};
template<typename TElement>
IteratorSet<TElement>::IteratorSet(Set<TElement>* mul) {
Set = mul;
crt = mul->prim;
}
template<typename TElement>
bool IteratorSet<TElement>::valid() {
return crt != NULL;
}
template<typename TElement>
TElement IteratorSet<TElement>::element() {
return crt->element;
}
template<typename TElement>
void IteratorSet<TElement>::next() {
crt = crt->next;
}
=======================================================
domain.h (names of Pizzas)
#include <string>
using namespace std;
class Pizza {
public:
Pizza(string namePizza) : namePizza(namePizza) {}
Pizza() : namePizza("") {}
string getName() const {
return namePizza;
}
int hashCode()
{
int sum = 0;
for (unsigned i = 0; i < str.length(); i++)
sum += str[i];
return sum;
}
bool operator == (Pizza& other) {
return namePizza == other.getName();
}
private:
string namePizza;
string str;
};
====================================================
main.cpp:
#include "SetADT.h"
#include <string>
#include <iostream>
#include "domain.h"
void show(Set<Pizza>* set) {
IteratorSet<string> it = set->iterator();
while (it.valid()) {
cout << "\t" << it.element().getName() << endl;
it.next();
}
}
int main()
{
Set<Pizza> set;
Pizza pizza1{ "diavola" };
Pizza pizza2{ "prosciuto" };
set.add(pizza1);
set.add(pizza2);
show(set);
return 0;
}
When I try to print the objects added to the Set it pops and error and the program stops.
I don't know anywhere else to look to find the problem.
Anyway, if the code sample isn't enough, here the complete project ( has parts of romanian in it )
http://www20.zippyshare.com/v/qKpEcZhr/file.html
The reason might be, for example, prim variable that you use in the iterator, that is initialized to an undefined value. However, code you posted is not compilable, i.e. there are other problems why your code is not working. Did not download your zip file.
I'm attempting to make some sort of autocomplete feature in c++. First by using a Trie and once that works (and most importantly, I know HOW it all works) I'll try it using a Ternary tree. But as for now I get a segmentation fault when ever I add words starting with a different characte than those already in the Trie.
Eg. we add "abc", "abcd" and "abcde" this is no problem. Later when I want to add (while the "abc" etc are still in the Trie) "xfce", "xfced" a segmentation fault occurs.
I've been debugging this for some while now and can't seem to find the problem.
I think the problem resides somewhere in Trie.cpp so that's the file I'll provide here. However it might be in the main function aswell but I don't wanna get yelled at for posting to much code...
#include "Trie.h"
#include <iostream>
Trie::Trie()
{
this->root = new Node(false);
}
Trie::~Trie()
{
}
Trie::Node::Node(bool isLeaf)
{
this->isLeaf = isLeaf;
}
void Trie::insert(const std::string& word)
{
Node* crawler = this->root;
int index;
for(int i = 0; i < word.length(); ++i)
{
index = CHAR_TO_INDEX(word.at(i));
if(!crawler->children[index])
{
crawler->children[index] = new Node(false);
}
crawler = crawler->children[index];
}
crawler->isLeaf = true;
}
int Trie::contains(const std::string& word)
{
int index;
Node* crawler = this->root;
for(int i = 0; i < word.length(); ++i)
{
index = CHAR_TO_INDEX(word.at(i));
if(!crawler->children[index])
{
return -1;
}
crawler = crawler->children[index];
}
return (crawler != NULL && crawler->isLeaf);
}
std::vector<std::string> Trie::possibleSuffixes(std::string& prefix)
{
Node* crawler = this->root;
int index;
std::vector<std::string> result;
for(int i = 0; i < prefix.length(); ++i)
{
index = CHAR_TO_INDEX(prefix.at(i));
crawler = crawler->children[index];
}
traverse(prefix, crawler, result);
return result;
}
void Trie::traverse(std::string prefix, Node* node, std::vector<std::string>& v)
{
if(node->isLeaf)
{
v.push_back(prefix);
}
for(int i = 0; i < ALPHABET; ++i)
{
if(node->children[i])
{
traverse(prefix + (char)('a' + i), node->children[i], v);
}
}
}
Entire Trie class:
#ifndef TRIE_H
#define TRIE_H
#include <string>
#include <vector>
#define ARRAYSIZE(a) sizeof(a / sizeof(a[0]))
#define ALPHABET 26
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')
class Trie
{
private:
struct Node
{
Node(bool isLeaf);
struct Node *children[ALPHABET];
bool isLeaf;
};
Node *root;
void traverse(std::string prefix, Node* node, std::vector<std::string>& v);
public:
Trie();
~Trie();
int contains(const std::string& word); //Checks the existance of a specific word in the trie
void insert(const std::string& word); //Inserts new word in the trie if not already there
std::vector<std::string> possibleSuffixes(std::string& prefix);
};
Though you didn't mention about your Node class, I am assuming this -
class Node {
public:
bool isLeaf;
// must be >= 25 as you're inserting lowercase letters
// assuming your CHAR_TO_INDEX(ch) returns 0 based index
// e.g. 'a' => 0, 'b' => 1 ... 'z' => 25
Node* children[30];
// default constructor should be like this
Node(): isLeaf(false) {
for(int i = 0; i < 26; i++) {
children[i] = NULL;
}
}
~Node() {
for(int i = 0; i < 26; i++) {
if(children[i]) {
delete children[i];
children[i] = NULL;
}
}
delete this;
}
};
Please compare your Node class/struct whether its something like this.
I'm working on a programming lab on hash tables. The code we were given handles collisions by rehashing the key (by adding one) and trying again, simple, but works for lab. The problem is that, with the raw code, it could enter an infinite loop if you add a member to a full table. We were tasked to keep this from happening.
I'm using a count for contents (contentCount) so it wont get caught up in a loop, i.e. if count >= size, it won't insert.
The header and source files are below.
hashTable.h
#pragma once
#include <iostream>
using namespace std;
const int NONE = 0;
const int EMPTY = -1;
const int DELETED = -2;
class HashTable
{
public:
// Constructors
HashTable(int size);
HashTable(const HashTable & ht);
~HashTable();
// Methods
bool Insert(int key, int value);
bool Search(int key, int &value);
bool Delete(int key);
void Print();
private:
// Private methods
int Hash(int key);
int Hash2(int index);
// Private data
int Size;
int *Value;
int *Key;
int contentCount;
};
hashTable.cpp
#include "hashTable.h"
HashTable::HashTable(int size)
{
Size = size;
Value = new int[Size];
Key = new int[Size];
for (int index=0; index < Size; index++)
{
Value[index] = NONE;
Key[index] = EMPTY;
}
}
HashTable::HashTable(const HashTable & ht)
{
contentCount = 0;
Size = ht.Size;
Value = new int[Size];
Key = new int[Size];
for (int index=0; index < Size; index++)
{
Value[index] = ht.Value[index];
Key[index] = ht.Key[index];
}
}
HashTable::~HashTable()
{
delete []Value;
delete []Key;
}
bool HashTable::Insert(int key, int value)
{
if(contentCount >= Size)
{
return false;
}
// Find desired key
int index = Hash(key);
while ((Key[index] != key) && (Key[index] != EMPTY))
index = Hash2(index);
// Insert value into hash table
Value[index] = value;
Key[index] = key;
contentCount++;
return true;
}
bool HashTable::Search(int key, int &value)
{
// Find desired key
int index = Hash(key);
while ((Key[index] != key) && (Key[index] != EMPTY))
index = Hash2(index);
// Return value from hash table
if (Key[index] == key)
value = Value[index];
return (Key[index] == key);
}
bool HashTable::Delete(int key)
{
// Find desired key
int index = Hash(key);
while ((Key[index] != key) && (Key[index] != EMPTY))
index = Hash2(index);
// Delete value from hash table
if (Key[index] == key)
{
Value[index] = NONE;
Key[index] = DELETED;
contentCount--;
return true;
}
return false;
}
int HashTable::Hash(int key)
{
return key % Size;
}
int HashTable::Hash2(int index)
{
cout << "COLLISION\n";
return (index+1) % Size;
}
void HashTable::Print()
{
cout << "Index\t" << "Value\t" << "Key\n";
for (int index=0; index < Size; index++)
cout << index << "\t"
<< Value[index] << "\t"
<< Key[index] << "\n";
}
Thanks ahead for the help!
You're initializing contentCount in the copy constructor, but in HashTable(int size), you're not.
So obviously, it will be uninitialized.
This does not work. It gives an error regarding ISO C++ forbidding initialization.
class hash_map
{
private:
hash_entry **table;
const int TABLE_SIZE = 128;
public:
hash_map()
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
}
int get(int key)
{
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] == NULL)
return -1;
else
return table[hash]->getValue();
}
void put(int key, int value)
{
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] != NULL)
delete table[hash];
table[hash] = new hash_entry(key, value);
}
~hash_map()
{
for (int i = 0; i < TABLE_SIZE; i++)
if (table[i] != NULL) delete table[i];
delete[] table;
}
};
const int TABLE_SIZE = 128;
This is the cause of the compilation error. It is allowed in C++11 only, not in C++03 and C++98.
Either make it a static member of the class, OR initialize it in the constructor. Make use of member-initialization-list for it.
Apart from that dont forget to implement copy-semantics following Rule of Three, OR disable it altogether by declaring them (don't define them) in the private section. I think, disabling it would make more sense in this case.
You need to initialize it in constructor, change
const int TABLE_SIZE = 128;
to
const int TABLE_SIZE;
and the constructor from
hash_map()
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
to
hash_map() : TABLE_SIZE(128)
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
You need to put the initialization into the constructor like this:
class hash_map
{
private:
hash_entry **table;
const int TABLE_SIZE;
public:
hash_map(): TABLE_SIZE(128)
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
...
You could have been more specific and provide a minimal example that reproduces the problem and an exact error that compiler gives you. But anyway, even without a psychic mode turned on, it is obvious that error in on this line:
const int TABLE_SIZE = 128;
You cannot initialize a class member like that, it has to be done in constructor initialization list, unless this member is a static constant compile-time expression (constexpr in C++11).
So remove = 128 from that line and modify constructor to do this:
hash_map() : TABLE_SIZE (128)
{
....
Use enumerated type:
class hash_map
{
private:
enum
{
TABLE_SIZE = 128;
};
hash_entry * table[TABLE_SIZE];
//...
};