hash map no viable overloaded '=' - c++

public:
typedef ics::pair<KEY,T> Entry;
typedef int (*hashfunc) (const KEY& a);
private:
int (*hash)(const KEY& k); //Hashing function used (from template or constructor)
enum bin_state {bs_empty, bs_occupied, bs_was_occupied};
Entry* map = nullptr; //Entry array
bin_state* state = nullptr; //bin_state[] describes the state of map[i]
double load_threshold; //used/bins <= load_threshold
int bins = 1; //# bins in array (should start at 1 so hash_compress doesn't % 0)
int used = 0; //Cache for number of key->value pairs in the hash table
int mod_count = 0; //For sensing concurrent modification
//Helper methods
int hash_compress (const KEY& key) const; //hash function ranged to [0,bins-1]
int find_key (const KEY& key) const; //Returns index to key's bin or -1
int next_unoccupied (int bin) const; //this bin or next beyond that is unoccupied
void ensure_load_threshold(int new_used); //Reallocate if load_factor > load_threshold
HashOpenMap<KEY,T,thash>::HashOpenMap(double the_load_threshold, int (*chash)(const KEY& k)): hash(thash != (hashfunc)undefinedhash<KEY> ? thash : chash), load_threshold(the_load_threshold)
{
if (hash == (hashfunc)undefinedhash<KEY>)
throw TemplateFunctionError("HashMap::default constructor: neither specified");
if (thash != (hashfunc)undefinedhash<KEY> && chash != (hashfunc)undefinedhash<KEY> && thash != chash)
throw TemplateFunctionError("HashMap::default constructor: both specified and different");
map = new Entry[bins];
for (int b=0; b<bins; ++b)
map[b] = new bin_state[];
}
I am new to c++. I am currently writing the Constructors for the HashOpenMap. For the above code, I got the following error:
no viable overloaded '='
map[b] = new bin_state[];
any idea how to fix it? thanks in advance.

Make sure you instantiate the same type as the target array element
map[b] = new Entry{};
Also, consider not using new/delete in C++. Or raw C arrays.

Related

Resizing and copying elements in a Hashtable Array

Right now I have struct IndexLocation that defines a page number pageNum and a word number wordNum on a page, and a struct IndexRecord that consists of a specific word and its locations that is a vector of IndexLocations.
In IndexRecord.h:
struct IndexLocation {
int pageNum; //1 = first page
int wordNum; //1 = first word on page
IndexLocation(int pageNumber, int wordNumber);
};
struct IndexRecord {
//indexed word
std::string word;
//list of locations it appears
std::vector<IndexLocation> locations;
IndexRecord();
//Constructor - make a new index record with no locations
explicit IndexRecord(const std::string& wordVal);
//Add an IndexLocation to the record
// Does NOT check for duplicate records
void addLocation(const IndexLocation& loc);
//Returns true if the record contains the indicated location
bool hasLocation(const IndexLocation& loc) const;
};
Then, I have a Hash Map IndexMap which stores values of IndexRecords using the word as the key. Within one, an IndexRecord may be stored at bucket 3, have a word apple, and have locations be 1,2 and 2,5.
#include "IndexRecord.h"
class IndexMap
{
private:
int numBuckets;
int keyCount;
IndexRecord* buckets;
//handle resizing the hash table into a new array with twice as many buckets
void grow();
//Get the location this key should be placed at.
// Will either containt IndexRecord with that key or an empty IndexRecord
unsigned int getLocationFor(const std::string& key) const;
public:
//Construct HashMap with given number of buckets
IndexMap(int startingBuckets = 10);
//Destructor
~IndexMap();
//Copy constructor and assignment operators
IndexMap(const IndexMap &other);
IndexMap& operator=(const IndexMap& other);
//Returns true of indicated key is in the map
bool contains(const std::string& key) const;
//Add indicated location to the map.
// If the key does not exist in the map, add an IndexRecord for it
// If the key does exist, add a Location to its IndexRecord
void add(const std::string& key, int pageNumber, int wordNumber);
void IndexMap::add2(const std::string &key, IndexLocation location)
};
Furthermore, in IndexMap.cpp, I have the add function, the add2 function, and grow function.
void IndexMap::add(const std::string &key, int pageNumber, int wordNumber) {
if (keyCount == numBuckets)
grow();
int bucketNumber = getLocationFor(key);
if (this->contains(key) == true)
buckets[bucketNumber].addLocation(IndexLocation(pageNumber, wordNumber));
else if (this->contains(key) == false) {
while (buckets[bucketNumber].word != "?") {
if (bucketNumber < numBuckets)
bucketNumber++;
else if (bucketNumber == numBuckets)
bucketNumber = 0;
}
string foo = key;
buckets[bucketNumber].word = key;
buckets[bucketNumber].addLocation(IndexLocation(pageNumber, wordNumber));
keyCount++;
}
return;
}
void IndexMap::add2(const std::string &key, IndexLocation location) {
if (keyCount > 0.7 * numBuckets)
grow();
int bucketNumber = getLocationFor(key);
if (this->contains(key) == true)
buckets[bucketNumber].addLocation(location);
else if (this->contains(key) == false) {
while (buckets[bucketNumber].word != "?") {
if (bucketNumber < numBuckets)
bucketNumber++;
else if (bucketNumber == numBuckets)
bucketNumber = 0;
}
string foo = key;
buckets[bucketNumber].word = key;
buckets[bucketNumber].addLocation(location);
keyCount++;
}
return;
}
void IndexMap::grow() {
IndexRecord* oldTable = buckets;
int oldSize = numBuckets;
numBuckets = numBuckets * 2 + 1;
IndexRecord* newArray = new IndexRecord[numBuckets];
keyCount = 0;
for (int i = 0; i < oldSize; i++) {
if (oldTable[i].word != "?") {
this->add2(oldTable[i].word, oldTable[i].locations[i]); // having trouble here
}
}
buckets = newArray;
delete [] oldTable;
}
My issue begins here. I believe my basic logic is sound: keep the old array around with a pointer, make a new, larger one and reset the size of the HashTable, iterate through the old array and add anything it contains back into the hashtable with the add function, and then delete the old array, but this just results in a segmentation fault (SIGSEGV) once keyCount hits numBuckets. (The reason I have an add2 function which is almost identical to my add function and use it in grow is because I didn't know how to modify get a pageNumber and a wordNumber for the this->add2 line within grow; the assignment specifications say we cannot modify the original add function's header).
You never assign to buckets in grow, so the newly enlarged array is not accessible by your other functions.

Accessing array values within class, c++

I am implementing a set in C++ using an array where elements with values of 0 are not in the set and those with 1 are in the set. For example, if my set is {1,5} my array would look like: [0, 1, 0, 0, 0, 1]. I am overloading the "/" operator to show the set difference, so if x is in set A and x is not in set B then x is in A/B. I pass the second Set object to the overloaded function by reference, but I am unable to access it's member variable "arr" which stores the array.
This is the header file:
class Set
{
public:
Set();
virtual ~Set();
Set(int);
int* arr;
int len;
Set operator/(const Set&);
friend ostream& operator<<(ostream&, const Set&);
int* getArray() const;
};
And here is the .cpp file:
Set::Set(int n) {
arr = new int[n+1];
len = n+1;
}
Set Set::operator/(const Set &s){
int* arr2 = s.getArray();
for (int i = 0; i < this->len; i++) {
if (this->arr[i] == 1) {
if (arr2[i] == 0) {
this->arr[i] = 1;
}
else {
this->arr[i] = 0;
}
}
}
return *this;
}
int* Set::getArray() const { return arr; }
If I attempt to print the values of arr2 I get values that appear to be addresses. How do I access the actual values of arr2?
Edit: I have not learned the "Rule of 3" in any class I've taken so I have no understanding how this could make my code not work. I've just done some research on it, but I would appreciate a short explanation on how to implement that in this case. Also, I am not allowed to use containers, so I can't use a vector as suggested in the comments.

Sorting doesn't work with templated class

I have an insertion sort function
void insertionSort(ArrayList<int> myData)
{
for (int i = 1; i < myData.getSize(); i++) {
int index = myData[i];
int j = i;
while (j > 0 && myData[j-1] > index) {
myData.swap(j - 1, j);
j--;
}
myData[j] = index;
}
}
which uses this swap function
template<class TYPE>
void ArrayList<TYPE>::swap(int from, int to) throw(std::out_of_range)
{
int temp = 0;
temp = this->items[from];
this->items[from] = this->items[to];
this->items[to] = temp;
swapNum++;
}
This is how my private methods look like
TYPE * items;
int currentLength;
static int swapNum;
I have an overloaded [] operator and a getSize() function that I think I wrote well and not contributing to my problem. Now if I do this in my main.cpp
ArrayList<int>m_Data(1);
and append say 4,2,9,1 on the m_Data and call
insertionSort(m_Data);
I get two errors
1. Error C2440 '=': cannot convert from 'std::string' to 'int'
on the swap function and
2. The insertion sort doesn't work
First problem: it should be something like TYPE temp = this->items[from]. After repairing it (I used STL swap) function works. Well, it works on STL vector and swap. If you still do have problem, then your array structure is probably invalid.
EDIT: In function 'insertionSort' shouldn't you have template (as in swap function)?

Implement hash-table in C++

The following is the implementation of hashtable using C++. Can you please help me to understand what HashEntry **table is? Why it is declared as a double pointer? Is it a array and each value of the array is HashEntry?
class HashEntry {
private:
int key;
int value;
public:
HashEntry(int key, int value) {
this->key = key;
this->value = value;
}
int getKey() {
return key;
}
int getValue() {
return value;
}
};
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;
}
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 HashEntry(key, value);
}
~HashMap() {
for (int i = 0; i < TABLE_SIZE; i++)
if (table[i] != NULL)
delete table[i];
delete[] table;
}
};
In this code, table is a pointer to a pointer to HashEntry
HashEntry **table;
The general rule is to start with the variable name and the basic type, go right as much as possible then go left, see this excellent description
http://unixwiz.net/techtips/reading-cdecl.html
So you start with the variable, table, and the basic type, HashEntry which is furthest to the left. Note that the article describes the rules for 'C' where a basic type can be a struct, think of your C++ class HashEntry as a 'C' struct.
table is ... HashEntry
There is nothing else to the right of table in the declaration, so go left, and you have "*" which stands for pointer to:
table is pointer to ... HashEntry
Again you must go left in the declaration and consume the next "*", you now have
table is pointer to pointer to HashEntry
... and you are done.
It is perhaps unfortunate that table was declared that way, because table implies array, and it is not declared as an array. It turns out that in C++, as in C, an array "decays" into a pointer when it is passed to a function. Here "decays" means you have lost information, namely the size of the array.
An equivalent declaration, which I think would give the reader more insight would be:
HashEntry * table[];
Using the rules about how to interpret variable declarations, this should be read as
table is undimensioned array of pointer to HashEntry
This is equivalent from the compiler's point of view to the previous declaration, because an undimensioned array is passed as a pointer to the type of the elements of the array (the value being the address of the first element, at offset 0). A "dimensioned array" also decays to a pointer, with the loss of the dimension information. See this SO answer for more information on decaying of arrays to pointers.
What is array decaying?

No Appropriate Default Constructor Available despite default constructor made?

Trying to make my own Map struct to store my own-created 'Strings,' and after 8 hours or so finally got it down to only a few compiler errors (six of them). I've spent the last hour and forty minutes searching the web for answers, only to find people forgot default constructors, and tried mixing things up in my own program. Since I'm not really sure where the problem is in advance, I apologize for posting all this code...I put what I thought were the most relevant files first; I think only the first 3 are necessary. The error is
"SubdomainPart' : No appropriate default constructor available" for lines 12 and 20 of the Map.h file.
Map.h
// Map.h - Map template class declaration
// Written by -----
#pragma once
template<typename KEY_TYPE, typename VALUE_TYPE>
struct Map
{
public:
// Default / initial constructor hybrid
Map(int initialCapacity = 10)
{
Size = 0;
Capacity = initialCapacity;
Key;
MappedValue;
//Allocate the C-Array elements using HEAP
Data = new VALUE_TYPE[Capacity];
}
struct iterator
{
KEY_TYPE * current;
KEY_TYPE * prev;
KEY_TYPE * next;
iterator operator ++ ()
{
iterator it = this;
iterator itNext = it.next;
it.next = itNext.next; // pushes iterator forward.
it.prev = it.current;
it.current = it.next;
}
iterator operator -- ()
{
iterator it = this;
iterator itPrev = it.prev;
it.prev = itPrev.prev; // pushes iterator backward.
it.next = it.current;
it.current = it.prev;
}
};
Map(const Map& copyFrom)
{
// Necessary to prevent the delete[] Data; statement in the assignment operator from
// freezing because Data has some garbage address in it.
Data = NULL;
*this = copyFrom; //'this' points to the current instance of the object. (in this case, 'Map')
}
// Destructor: MUST HAVE because we allocate memory
~Map()
{
delete[] Data;
}
Map& operator = (const Map& copyFrom)
{
// 0) delete the old one!
delete[] Data;
// 1) copy Size and Capacity
Size = copyFrom.Size;
Capacity = copyFrom.Capacity;
// 2) Allocate Memory
Map* Data = new Map[Capacity];
// 3) Copy the Map Elements
for(int i = 0; i<Size; i++)
Data[i] = copyFrom.Data[i];
return *this;
}
// Index Operator
VALUE_TYPE& operator[] (KEY_TYPE key) const
{
return Data[key];
}
// Accessor functions: read-only access to Size and Capacity
int GetSize() const //const does not modify ANY data members of the class (size, capacity, or data)
{
return Size;
}
int GetCapacity() const
{
return Capacity;
}
void PushBack(const VALUE_TYPE& newElement) //adds value to end of Map as default
{
if(Size >= Capacity)
increaseCapacity(2 * Capacity);
Data[Size] = newElement;
Size++; // increases size of the array so it can be used later.
}
// Overloaded Add function, inserts a value at specified index, calls in "Insert" to do so.
void Add(const VALUE_TYPE& newElement, int index)
{
if( (index<0) || (index > Size))
{
throw ("Index to insert is out of range");
}
//Make sure there's space!
if (Size >= Capacity)
increaseCapacity(2*Capacity); //increase size of array if too small!
Insert(index, newElement);
}
void Remove(int index) // index = index to be removed.
{
// Make sure it's inside the bounds
if( (index<0) || (index > Size))
{
throw ("Index to Remove is out of range.");
}
// it's going to remove the unneeded space by having its capacity one above the Size.
Map* new_Data = new Map[Size];
//Copy data onto new pointer section.
for(int x = 0; x<Size; x++)
new_Data[x] = Data[x];
delete[] Data; //deallocates old memory and uneeded capacity slots.
for(int x = index; x < (Size - 1); x++) //removes the value at index 'index.' Now Data has a capacity of the amount of slots used and one more for a NULL value.
new_Data[x] = new_Data[x+1];
Data = new_Data;
Data[Size-1] = NULL;
Size--;
}
void increaseCapacity(int new_capacity)
{
if(new_capacity>Capacity)
{
if(new_capacity> 2* Capacity)
Capacity = new_capacity;
else
Capacity *= 2;
//create Map with a new capacity!
Map* new_Map = new Map[Capacity];
for(int x = 0; x<Size; x++)
{
new_Map[x] = Data[x];
}
//clear out old memory
delete[] Data;
//set data pointer to the new Map
Data = new_Map;
}
}
KEY_TYPE * Key; // Used to identify mapped values.
VALUE_TYPE MappedValue; // The value actually contained.
private:
int Size; // The count of actual C-Array elements used
int Capacity; // The count of C-array elements allocated
// The encapsulated C-array
VALUE_TYPE * Data; // pointer of type 'DATA_TYPE' called data (will be name of our array).
void Insert(const int index, const VALUE_TYPE& insertValue)
{
if( (index<0) || (index > Size))
{
throw out_of_range ("Index to insert is out of range");
}
//Time to shuffle the array down!
for(int x = Size; x>index; x--)
{
Data[x] = Data[x-1];
}
//Insert the new item at index 'Index!'
Data[index] = insertValue;
Size++;
}
};
SubdomainPart.h
// SubdomainPart.h - SubdomainPart validation class declaration
// Written by -------
#pragma once
#include "String.h"
using namespace std;
class SubdomainPart
{
public:
// Takes the address and stores into the Address data member
SubdomainPart(const String& address);
// Returns true when the Address is valid or false otherwise
virtual bool IsValid();
private:
String Address;
};
SubdomainPart.cpp
// SubdomainPart.cpp - Subdomain validation class implementation
// Written by ---------
#pragma once
#include "SubdomainPart.h"
// Takes the address and stores into the Address data member
SubdomainPart::SubdomainPart(const String& address)
{
Address = address;
}
// Returns true when the Address is valid or false otherwise
bool SubdomainPart::IsValid()
{
int currentDotIndex = 0;
int nextDotIndex = 0;
int found = 0; // first index of a found invalid character
int hyphenIndex = 0; // used to check hyphen rule
// 1. Check the size, 255 total characters
if(Address.GetLength() < 1 || Address.GetLength() > 255)
return false;
// Checks for valid amount of 1-63 characters between dots
currentDotIndex = Address.FindFirstOf('.');
if(currentDotIndex == 0 || currentDotIndex == Address.GetLength()-1)
return false;
else if(currentDotIndex!=(-1))
nextDotIndex = Address.Find('.', currentDotIndex+1);
else
nextDotIndex = (-1); // if no '.' is found, ensures the following loop doesn't run.
while(nextDotIndex!=(-1))
{
if((nextDotIndex-currentDotIndex) == 1 || (nextDotIndex-currentDotIndex) > 63)
return false;
currentDotIndex = nextDotIndex;
nextDotIndex = Address.Find('.', currentDotIndex+1);
}
// 2. Check for valid characters
found = Address.FindFirstNotOf("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-.");
if(found!=(-1)) // if a character not listed above is found.
return false;
// 3. Check for dash rule
// Making sure hyphens aren't located at the first or last index of a subdomain.
hyphenIndex = Address.FindFirstOf('-');
if(hyphenIndex == 0)
return false;
hyphenIndex = Address.FindLastOf('-');
if(hyphenIndex == Address.GetLength()-1)
return false;
// Makes sure two hyphens aren't in a row.
for(int x = 1; x<Address.GetLength(); x++)
if(Address[x] == '-' && Address[x] == Address[x-1])
return false;
return true;
}
I don't see a default constructor in this class:
class SubdomainPart
{
public:
// Takes the address and stores into the Address data member
SubdomainPart(const String& address);
// Returns true when the Address is valid or false otherwise
virtual bool IsValid();
private:
String Address;
};
Keep in mind that this map constructor is default-constructing every member rather than initializing them:
Map(int initialCapacity = 10)
{
Size = 0;
Capacity = initialCapacity;
Key;
MappedValue;
//Allocate the C-Array elements using HEAP
Data = new VALUE_TYPE[Capacity];
}
You don't have a default constructor for SubdomainPart you have only provided a copy constructor. A default constructor takes no argument.
The compiler is complaining that SubdomainPart doesn't have a default constructor, and indeed it doesn't. It's required because your Map contains an object of type VALUE_TYPE:
VALUE_TYPE MappedValue;
Also, your Map constructor contains very weird code. I assume you actually wanted to use an initialiser list:
Map(int initialCapacity = 10)
: Key()
, MappedValue()
, Size(0)
, Capacity(initialCapacity)
, Data(new VALUE_TYPE[Capacity])
{}
The problem is with Data = new VALUE_TYPE[Capacity]; part.
The compiler generates code to allocate the array and instantiate each element by calling the parameterless constructor for VALUE_TYPE. As SubdomainPart doesn't have one (since you have defined a custom one), the compiler throws an error.
The reason that compiler reports error in map.h is that it is exactly the place where the constructor is called from. It is not used in SubdomainPart code, it is just defined there.